python装饰器和描述器的使用总结,python装饰,如果需要保留函数名,则在
python装饰器和描述器的使用总结,python装饰,如果需要保留函数名,则在
被某些中文教程坑过,我的建议是有问题看官方文档,即使没有很详细的例子,至少不坑
装饰器
毫无疑问在python中用得非常多
def deco(func): def _deco(): print 'before invoked' func() print 'after invoked' return _deco @deco def f(): print 'f is invoked'
在f
上加deco
装饰器相当于f = deco(f)
, 和functools.partial
有些类似
如果被装饰的函数f
带参数且有返回值
def deco(func): def _deco(*args, **kwargs): print 'before invoked' ret = func(*args, **kwargs) print 'after invoded' return ret return _deco @deco def f(a): print 'f is invoked' return a + 1
如果装饰器带有参数,需要多包一层,把参数调用包进去
def deco(*args): def _deco(func): def __deco(*args, **kwargs): print 'decorator args is', args print 'before invoked' ret = func(*args, **kwargs) print 'after invoded' return ret return __deco return _deco @deco('test') def f(a): print 'f is invoked' return a + 1
只有最里面一层的__deco
才会每次都调用,其它外层函数只在包装时调用一次,当然,你可以在其中声明变量,然后拿到__deco
里使用。如果需要保留函数名,则在__deco
上加@functools.wraps
装饰器
使用 类 作装饰器,注意是类此时相当于装饰函数,被装饰的函数会作为实例化参数,得到一个类实例,以python wiki上一个做登录检查的代码为例
class LoginCheck: def __init__(self, f): self._f = f def __call__(self, *args): Status = check_function() if Status is 1: return self._f(*args) else: return alt_function() def check_function(): return test def alt_function(): return 'Sorry - this is the forced behaviour' @LoginCheck def display_members_page(): print 'This is the members page'
描述器
描述器在监视特定属性的时候很有用,其只在新式类中起作用。所有的描述器协议如下:
descr.__get__(self, obj, type=None) --> value
descr.__set__(self, obj, value) --> None
descr.__delete__(self, obj) --> None
如果一个对象同时定义了 __get__()
和 __set__()
,它叫做资料描述器(data descriptor)。仅定义了 __get__()
的描述器叫非资料描述器
描述器在属性访问时被自动调用。举例来说, obj.x
会在 obj
的字典中找x
,如果x
定义了 __get__
方法,那么 x.__get__(obj)
会依据下面的优先规则被调用
调用优先级:
资料描述器 -> 实例字典 -> 非资料描述器
常用的描述器就是property
了,一般都只实现了__get__
的接口
先给出一个classmethod
的实现和一个用于测试描述器优先级的类
class classproperty(object): def __init__(self, func): self.func = func def __get__(self, instance, owner): return self.func(owner) class MyClass(object): @classproperty def name(cls): return cls.__name__ @property def x(self): return self._data @x.setter def x(self, value): self._data = value @x.deleter def x(self): del self._data def __init__(self, val): self._data = val self.x = 3 self.name = 'test'
接下来调用
s = MyClass(99) print s.x print s.name print s.__dict__
很明显x
是资料描述器,而name
不是,所以结果是
3
5
{‘_data’: 3, ‘name’: ‘test’}
如果给classproperty
加上__set__
,那么就会调用被装饰的name
,而不是实例化时实例字典中的name
一个property
的python 实现
class Property(object): "Emulate PyProperty_Type() in Objects/descrobject.c" def __init__(self, fget=None, fset=None, fdel=None, doc=None): self.fget = fget self.fset = fset self.fdel = fdel self.__doc__ = doc def __get__(self, obj, objtype=None): if obj is None: return self if self.fget is None: raise AttributeError, "unreadable attribute" return self.fget(obj) def __set__(self, obj, value): if self.fset is None: raise AttributeError, "can't set attribute" self.fset(obj, value) def __delete__(self, obj): if self.fdel is None: raise AttributeError, "can't delete attribute" self.fdel(obj) def getter(self, fget): return type(self)(fget, self.fset, self.fdel, self.__doc__) def setter(self, fset): return type(self)(self.fget, fset, self.fdel, self.__doc__) def deleter(self, fdel): return type(self)(self.fget, self.fset, fdel, self.__doc__)
评论关闭