我有一个对象层次结构,其中几乎所有方法都是类方法。它看起来如下:
class ParentObject(object):
def __init__(self):
pass
@classmethod
def smile_warmly(cls, the_method):
def wrapper(kls, *args, **kwargs):
print "-smile_warmly - "+kls.__name__
the_method(*args, **kwargs)
return wrapper
@classmethod
def greetings(cls):
print "greetings"
class SonObject(ParentObject):
@classmethod
def hello_son(cls):
print "hello son"
@classmethod
def goodbye(cls):
print "goodbye son"
class DaughterObject(ParentObject):
@classmethod
def hello_daughter(cls):
print "hello daughter"
@classmethod
def goodbye(cls):
print "goodbye daughter"
if __name__ == '__main__':
son = SonObject()
son.greetings()
son.hello_son()
son.goodbye()
daughter = DaughterObject()
daughter.greetings()
daughter.hello_daughter()
daughter.goodbye()
给出的代码输出如下:
greetings
hello son
goodbye son
greetings
hello daughter
goodbye daughter
我希望代码输出以下内容:
-smile_warmly - SonObject
greetings
-smile_warmly - SonObject
hello son
-smile_warmly - SonObject
goodbye son
-smile_warmly - DaughterObject
greetings
-smile_warmly - DaughterObject
hello daughter
-smile_warmly - DaughterObject
goodbye daughter
但是我不希望在每个方法之前添加行@smile_warmly
(当我尝试在上面的代码中执行此操作时,我收到错误消息TypeError: 'classmethod' object is not callable
)。相反,我希望在__init__()
方法中以编程方式进行每种方法的修饰。
是否有可能以编程方式在Python中修饰方法?
编辑:找到似乎有效的内容 - 请参阅下面的答案。感谢BrenBarn。
答案 0 :(得分:22)
所有装饰者都会返回一个新函数。这样:
@deco
def foo():
# blah
与此相同:
def foo():
# blah
foo = deco(foo)
您可以随时使用@
语法执行相同的操作,只需将函数替换为您喜欢的任何内容即可。因此,在__init__
或其他任何地方,您可以遍历所有方法,并为每个方法替换为smilewarmly(meth)
。
但是,不是在__init__
中进行,而是在创建类时更有意义。您可以使用元类来完成此操作,或者更简单地使用类装饰器:
def smileDeco(func):
def wrapped(*args, **kw):
print ":-)"
func(*args, **kw)
return classmethod(wrapped)
def makeSmiley(cls):
for attr, val in cls.__dict__.iteritems():
if callable(val) and not attr.startswith("__"):
setattr(cls, attr, smileDeco(val))
return cls
@makeSmiley
class Foo(object):
def sayStuff(self):
print "Blah blah"
>>> Foo().sayStuff()
:-)
Blah blah
在这个例子中,我将classmethod装饰放在我的smileDeco
装饰器中。您也可以将其放在makeSmiley
中,以便makeSmiley
返回smileDeco(classmethod(val))
。 (你想要这样做的方式取决于微笑装饰器与classmethods的关联程度。)这意味着你不必在课堂上使用@classmethod
。
当然,在makeSmiley
的循环中,您可以包含您想要决定的任何逻辑(例如,基于方法的名称)是否用微笑行为包装它。
请注意,如果您真的想在类中手动使用@classmethod
,则必须更加小心,因为通过类__dict__
访问的类方法不可调用。所以你必须专门检查对象是否是classmethod对象,而不是只检查它是否可调用。
答案 1 :(得分:0)
此解决方案产生我想要的输出:
class ParentObject(object):
def __init__(self):
self._adjust_methods(self.__class__)
def _adjust_methods(self, cls):
for attr, val in cls.__dict__.iteritems():
if callable(val) and not attr.startswith("_"):
setattr(cls, attr, self._smile_warmly(val))
bases = cls.__bases__
for base in bases:
self._adjust_methods(base)
def _smile_warmly(self, the_method):
def _wrapped(self, *args, **kwargs):
print "-smile_warmly - " +self.__name__
the_method(self, *args, **kwargs)
cmethod_wrapped = classmethod(_wrapped)
# cmethod_wrapped.adjusted = True
return cmethod_wrapped
def greetings(self):
print "greetings"
class SonObject(ParentObject):
def hello_son(self):
print "hello son"
def goodbye(self):
print "goodbye son"
class DaughterObject(ParentObject):
def hello_daughter(self):
print "hello daughter"
def goodbye(self):
print "goodbye daughter"
if __name__ == '__main__':
son = SonObject()
son.greetings()
son.hello_son()
son.goodbye()
daughter = DaughterObject()
daughter.greetings()
daughter.hello_daughter()
daughter.goodbye()
输出结果为:
-smile_warmly - SonObject
greetings
-smile_warmly - SonObject
hello son
-smile_warmly - SonObject
goodbye son
-smile_warmly - DaughterObject
greetings
-smile_warmly - DaughterObject
hello daughter
-smile_warmly - DaughterObject
goodbye daughter