python装饰器和描述器的使用总结
被某些中文教程坑过,我的建议是有问题看官方文档,即使没有很详细的例子,至少不坑
装饰器
毫无疑问在python中用得非常多
1
2
3
4
5
6
7
8
9
10
|
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
带参数且有返回值
1
2
3
4
5
6
7
8
9
10
11
12
|
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
|
如果装饰器带有参数,需要多包一层,把参数调用包进去
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
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上一个做登录检查的代码为例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
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
的实现和一个用于测试描述器优先级的类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
|
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’
|
接下来调用
1
2
3
4
|
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 实现
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
|
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__)
|
转载自演道,想查看更及时的互联网产品技术热点文章请点击http://go2live.cn
Zithromax Official Website [url=http://nefoc.com]cialis propecia o viagra[/url] Amoxicillin Safe During Pregnancy
Secure Place To Buy Yasmin Online Miglitol [url=http://viaonlineusa.com]viagra[/url] Progesterone Gestagen Buy Cialis Canada Amoxicillin Tight Throat
Propecia Rabia Erythromycin Price In Las Vegas Buy Tadalafil Generic [url=http://4rxday.com]cialis 5mg best price[/url] Canada Pharmacy 24 Hours Propecia Long Term Effectiveness Kwikmed Coupon Viagra
Cialis Super Active Difference Cat Cephalexin [url=http://bycheapvia.com]viagra online[/url] Levitra Acquistare
Prix Vente Xenical Pharmacie Hplc Methods For Amoxicillin Clavulanic Acid Buying Cialis Stateside [url=http://cheapciali.com]cialis price[/url] Viagra 100mg Over Night Generic Zentel Price Legally Overseas
Priligy Dapoxetine Sans Ordonnance Child’S Dosage Of Keflex [url=http://clanar.com]viagra[/url] Clomid Buy India Kamagra Oral Jelly Fast Delivery Cialis Precio Lilly
Proscar Para La Alopecia Propecia Amoxicillin And Clavulanate Acid Cheaper Viagra [url=http://cheapviapill.com]generic viagra[/url] How To Buy Cheap Worldwide Doryx 100mg Low Price Viagra 100mg Cialis Originale Forum
Securemed Discount Fedex Shipping Bentyl Website Internet Overseas [url=http://cialusa.com]canadian pharmacy cialis[/url] Sinus Infection Amoxicillin