与应用于函数的修饰器相比,理解应用于类的修饰器并不容易。适用于使用Python定义类的修饰器
@foo
class Bar(object):
def __init__(self, x):
self.x = x
def spam(self):
statements
装饰器的用途是什么?如何使用它?
与应用于函数的修饰器相比,理解应用于类的修饰器并不容易。适用于使用Python定义类的修饰器
@foo
class Bar(object):
def __init__(self, x):
self.x = x
def spam(self):
statements
装饰器的用途是什么?如何使用它?
它以一种更简单的方式取代了绝大多数自定义元类的经典好用途。
想想这样:没有什么直接在类体中可以引用类对象,因为类对象在主体完成运行之后才存在(它是元类创建类对象的工作 - - 通常为type
,对于没有自定义元类的所有类)。
但是,在类装饰代码运行后创建的类对象(事实上,用类对象作为参数!),因此可以非常清楚指的是类对象(通常需要这样做)。
例如,请考虑:
def enum(cls):
names = getattr(cls, 'names', None)
if names is None:
raise TypeError('%r must have a class field `names` to be an `enum`!',
cls.__name__)
for i, n in enumerate(names):
setattr(cls, n, i)
return cls
@enum
class Color(object):
names = 'red green blue'.split()
,现在你可以参考Color.red
,Color.green
,& C,而不是0
,1
等(当然,你通常会添加更多的功能,使“enum
”,但在这里我只是展示了将类功能添加到类装饰器中的简单方法,而不需要定制元类!)
我能想到的一个用例是如果您想要包装一个类的所有方法用一个函数装饰器。假设你有以下装饰:
def logit(f):
def res(*args, **kwargs):
print "Calling %s" % f.__name__
return f(*args, **kwargs)
return res
及以下等级:
>>> class Pointless:
def foo(self): print 'foo'
def bar(self): print 'bar'
def baz(self): print 'baz'
>>> p = Pointless()
>>> p.foo(); p.bar(); p.baz()
foo
bar
baz
可以装饰所有的方法:
>>> class Pointless:
@logit
def foo(self): print 'foo'
@logit
def bar(self): print 'bar'
@logit
def baz(self): print 'baz'
>>> p = Pointless()
>>> p.foo(); p.bar(); p.baz()
Calling foo
foo
Calling bar
bar
Calling baz
baz
但是,这是个馊主意?相反,你可以这样做:
>>> def logall(cls):
for a in dir(cls):
if callable(getattr(cls, a)):
setattr(cls, a, logit(getattr(cls, a)))
return cls
>>> @logall
class Pointless:
def foo(self): print 'foo'
def bar(self): print 'bar'
def baz(self): print 'baz'
>>> p = Pointless()
>>> p.foo(); p.bar(); p.baz()
Calling foo
foo
Calling bar
bar
Calling baz
baz
UPDATE:的logall
更宽泛的版本:
>>> def wrapall(method):
def dec(cls):
for a in dir(cls):
if callable(getattr(cls, a)):
setattr(cls, a, method(getattr(cls, a)))
return cls
return dec
>>> @wrapall(logit)
class Pointless:
def foo(self): print 'foo'
def bar(self): print 'bar'
def baz(self): print 'baz'
>>> p = Pointless()
>>> p.foo(); p.bar(); p.baz()
Calling foo
foo
Calling bar
bar
Calling baz
baz
>>>
全面披露:我从来没有做到这一点,我刚才提出这个例子了。
@Manoj,很高兴你喜欢它,tx让我知道! – 2010-10-05 05:31:23