前言
众所周知,Python是一门动态语言,变量不需要声明类型,这种灵活的形式让多人进行大型Python开发时会面临类型不明确的问题,项目中类和方法很多了,方法的参数就会让人迷惑,如果开发者自身编码风格又比较随意,那么项目就会变得难以维护。
受公司项目启发,这里分享关于装饰器的几点思考。
“全局”静态方法
静态方法很简单,使用@staticmethod
装饰器则可,简单例子如下:
class MyClass(object):
name = '二两'
@staticmethod
def myfun():
print(f'I love {MyClass.name}')
使用时:
MyClass.myfun()
这种方式会让代码显得直观,此时类就变成了方法集合者,用于表示相同类别的方法。
通常,在一个大型项目中,不同模块会分层处理,比如数据库操作相关的内容放在Modules目录下,数据过滤方面的内容放在filters目录下,每个目录下,有相应的py文件,文件中有相应的类。
此时通过@staticmethod
装饰器,就可以让方法在调用时很清晰,让其他人可以一眼看出方法来自于哪里,比如下面这样写。
AdminFilter.filter_session(Utils.get_session())
AdminModule.get_user(user_id)
很清晰的知道,filter_session()在AdminFilter类下,用于判断session合法性,过滤非法用户。
对比一下Java,所有类中的方法都弄成静态方法的方式就是模仿Java项目开发的形式,可以很简单直观的明白方法的来源。
一个大型项目,所有类中的方法都弄成静态方法可能是一个不错的选择。
强制指定参数类型
Python中的方法不需要指定变量名,在代码量很多时,开发某个需求可能需要将参数一层层传递下去,此时方法参数类型不明确就比较尴尬,传参时,还要理解旧的逻辑是怎么使用这些参数的,从而大致判断参数的类型,如果方法本身就写的很庞大,那开发效率就会比较低了。
插句题外话,方法逻辑的长度最好要控制,别将所有的逻辑都写在一个方法上,最好将其分层,放到不同的方法中,方便阅读和单元测试。
回到刚刚的话,Python中方法参数没有类型会遇到上述问题,如果像Java一样就好了。
用类型标注?确实是个不错的方法,如下例子。
def myfun(id: int, params: dict) -> dict:
res = AdminModule.get(id, params)
return res
类型标注并不强制要求传相应类型的值,比如id标注要传int类型的值,但直接传入str类型的值也可以,如果逻辑没问题就不会抛出异常,这里通过AdminModule.get()方法通过id去获取相应的值,id为str其实也没影响,但我们想要一种强制方式,方法参数类型传错了,直接抛出异常,从而严格统一整个项目的代码风格。
弄个装饰器就好了。
import functools
class ParamTypeError(Exception):
pass
def clear_param(**params):
def decorate(func):
@functools.wraps(func)
def wrapper(**kwargs):
for name, value in kwargs.items():
if not isinstance(value, params[name]):
raise ParamTypeError(
'the {func_name} params type error.'.
format(func_name=func.__name__))
result = func(**kwargs)
return result
return wrapper
return decorate
clear_param是一个典型的带参数装饰器,该装饰器利用isinstance()方法对传入参数类型进行判断,如果类型不符,则直接抛出ParamTypeError。
使用如下。
@clear_param(a=int, b=int)
def myfun(a, b):
return a + b
res = myfun(a=1, b=2)
print(res)
整个项目通过这个装饰器实现方法参数类型的强制约束,这会让开发者开发时麻烦一点,但非常利于后期的维护与扩展,代码很清晰。
为复杂计算方法加缓存装饰器
缓存装饰器这件事情其实很常见,简单点的就是利用一个dict,以方法名与参数作为dict的唯一key,将方法计算的结果作为value,当该方法再次收到同样的参数时,直接将value返回则可。
上述方式太简单,没有涉及数据超时以及优先级的概念,比较好的方式是实现一个LRU(最近最少使用)队列来做,设置缓存空间大小,避免使用过多内存,此外,定时将不常用的缓存清除,这里有很多细节可以聊,在「懒编程」后面的内容中再详聊吧,如果你现在兴趣浓厚,可以看一下cachetools
与cacheout
这个两个Python实现的缓存模块,后面有机会,我会扒一扒其中一个的源码。
结尾
文中提出的这些装饰器用法只有两个目的,让Python大型项目更规范,人为的约束开发者随意释放自己的才华,此外就是加速复杂的计算方法,让项目运行的更快一些。
如果本文对你有所帮助与启发,点击「在看」支持二两。
最后,周围牛人真多,还要多跟大家探讨与学习。