python用类作为装饰器

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用类作为装饰器

相关文章:

你感兴趣的文章:

标签云: