python的decorator是python比较有名的语法糖之一,一般的模式是把一个需要加装饰器的 方法传入一个装饰器方法,然后系统调用的时候其实是调用的装饰之后的方法,这种方法 的好处就是有的时候我们可能需要加一些即时,或者加一些统计项的时候,可以不和业务 逻辑代码混在一起。举一个非常简单的例子,就是执行一些cgi的方法的时候大都需要判断 登录,所以我们代码里面可能有这么一段
def login_required(fn): def dec_func(*args,**keyargs): if notlogin(): return json.dumps({"code":CODE_NOT_LOGIN}) else: return fn(*args,**keyargs)@app.get("/path/of/this/func")@login_requireddef cgifn(t): return json.dumps({"code":CODE_SUCCESS})
今天看falsk源代码的时候发现还有另外一种用法,大概代码如下(为了简便,只摘抄了部分) 从下面我们可以看出,在name上面的装饰漆是一个类
class Flask(): @locked_cached_property def name(self): """The name of the application. This is usually the import name with the difference that it's guessed from the run file if the import name is main. This name is used as a display name when Flask needs the name of the application. It can be set and overridden to change the value. .. versionadded:: 0.8 """ if self.import_name == '__main__': fn = getattr(sys.modules['__main__'], '__file__', None) if fn is None: return '__main__' return os.path.splitext(os.path.basename(fn))[0] return self.import_nameclass locked_cached_property(object): """A decorator that converts a function into a lazy property. The function wrapped is called the first time to retrieve the result and then that calculated result is used the next time you access the value. Works like the one in Werkzeug but has a lock for thread safety. """ def __init__(self, func, name=None, doc=None): self.__name__ = name or func.__name__ self.__module__ = func.__module__ self.__doc__ = doc or func.__doc__ self.func = func self.lock = RLock() def __get__(self, obj, type=None): if obj is None: return self with self.lock: value = obj.__dict__.get(self.__name__, _missing) if value is _missing: value = self.func(obj) obj.__dict__[self.__name__] = value return value
这种使用方式和一般的使用方式还是有很大差别的,所以让我觉得有点好奇,好奇的点有几 个地方,第一个是既然是装饰器,那上面的locked_cached_property
装饰的时候调用了什 么,第二个是装饰之后如何使用。
首先谈谈装饰,装饰器应该是对python编译器在编译被装饰的对象的时候,以被装饰方法为 参数,传入装饰器方法,然后返回一个新的方法绑定到被装饰的方法的名字上面。那这里如 果是一个类的话,那就会调用类的初始化方法,生成一个此类的实例绑定到了名字上面。就 像如下的代码一样,我们的abc应该就变成了一个cached_property
的一个实例。这样如果 我们访问A类一个对象的abc的时候,python在对某个实例调用属性的时候,会先看属性指向 的对象是否有get方法,如果有的话,那么就会尝试返回这个属性指向对象的get方 法返回的值,所以下面使用a的abc的时候,是通过直接使用属性的方式,而不是方法调用的 方式,这应该得益于python里面所有都是对象的好处。
#encoding=utf8_missing = Noneclass cached_property(object): def __init__(self, func, name=None, doc=None): self.__name__ = name or func.__name__ self.__module__ = func.__module__ self.__doc__ = doc or func.__doc__ self.func = func def __get__(self, obj, type=None): if obj is None: return self value = obj.__dict__.get(self.__name__, _missing) if value is _missing: value = self.func(obj) obj.__dict__[self.__name__] = value return valueclass A(): @cached_property def abc(self): return 'yes'b = A()print b.abcprint b.abc()
原文地址:python用类作为装饰器, 感谢原作者分享。 每年的情人节圣诞节除夕,也和他共度。甚至连吵架也是重复的,