python中有关属性访问的下划线方法

python descriptor的妙用

args posted @ 2011年10月24日 20:36 in python with tags python descriptor , 2709 阅读

看bottle的源码时发现的。

import functools
import random

class cache(object):

    def __init__(self, func):
        functools.update_wrapper(self, func, updated=[])
        self.getter = func

    def __get__(self, obj, cls):
        value = self.getter(cls)
        setattr(cls, self.__name__, value)
        return value


class A(object):
    @cache
    def m(cls):
        return "this is a methods %d" % random.randint(1,9)

a = A()
print a.m



cache对象用__call__方法,所以可以作为一个decorator。将类A中方法m作为self对象的func属性。注意cache()返回产生的是一个对象,也就是被修改过的self,这个对象在类A中和名字m关联。也就是原来的方法m已经被这个对象替换掉了,当然m对象依然有一个指向原函数的引用。

然后产生一个类A的实例a,当第一次访问a的m属性的时候会调用m的__get__函数,也就是m是一个descriptor。在__get__函数的内部对A新建了一个和m同名的对象(同名的原因就是先开始用update_wrapper将方法m的__name__拷贝到了self的__name__),这个对象的值就是函数m的返回值。假设这里返回的是"this is a methods 3",之后的多次调用会发现函数返回的是一样的值。从而也就实现了方法变为对象的静态属性。

这里可以在__get__函数后定义__set__函数,这样m就变成一个data descriptor了,然后在用上面的方法会发现结果一样。因为这时候属性m还是在A.__dict__中。

如果把setattr(cls, self.__name__, value)换成setattr(object, self.__name__, value)。然后的每次引用m.a就会发现值不同,因为data descriptor在查找链中的优先级要比实例的原生属性高

Avatar_small
依云 说:
2012年4月07日 22:27

File "a.py", line 22
return "this is a methods %d" % random.randint(1,9)
^
SyntaxError: invalid character in identifier

中文括号。。。

Avatar_small
Emma 说:
2023年2月01日 22:15

The cache object found in the source code of bottle is an incredibly useful tool. It provides decorator functionality, allowing the method m in class A to be replaced with an object which still has a reference to the original function. This object is then used to generate a random real estate agent Ponte Vedra number to be used in the method m. This ensures that the method is always returning something new and unique each time it is called. It is an excellent example of how to use decorators to create an efficient and useful program.


登录 *


loading captcha image...
(输入验证码)
or Ctrl+Enter