Python—我可以从类实例以编程方式修饰类方法吗?
我有一个对象层次结构,其中几乎所有的方法都是类方法。如下所示:Python—我可以从类实例以编程方式修饰类方法吗?,python,decorator,class-method,Python,Decorator,Class Method,我有一个对象层次结构,其中几乎所有的方法都是类方法。如下所示: class ParentObject(object): def __init__(self): pass @classmethod def smile_warmly(cls, the_method): def wrapper(kls, *args, **kwargs): print "-smile_warmly - "+kls.__name__
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
给定的代码输出如下:
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
我希望代码输出以下内容:
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\u
(当我在上面的代码中尝试这样做时,我会收到错误消息TypeError:“classmethod”对象不可调用)。相反,我希望在\uuu init\uuu()
方法中以编程方式对每个方法进行修饰
可以用Python编程修饰方法吗
编辑:找到一些似乎有效的方法——请参阅下面我的答案。多亏了BrenBarn。装饰程序所做的就是返回一个新函数。这:
@deco
def foo():
# blah
与此相同:
def foo():
# blah
foo = deco(foo)
您可以在任何时候做同样的事情,无需使用@
语法,只需将函数替换为您喜欢的任何函数即可。因此,在\uuuuu init\uuuuuuuuu
或其他任何地方,您可以循环使用所有方法,并将每个方法替换为smilewarmly(meth)
但是,与其在\uuuu init\uuuu
中执行,不如在创建类时执行。您可以使用元类,或者更简单地使用类装饰器:
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))
。(你想用哪种方式来做这件事取决于微笑装饰器与类方法的联系有多紧密。)这意味着你不必在类内部使用@classmethod
当然,在makeSmiley
中的循环中,您可以包括您想要决定(例如,基于方法名称)是否使用微笑行为来包装它的任何逻辑
请注意,如果您真的想在类内手动使用@classmethod
,您必须更加小心,因为通过类\uuuu dict\uuu
访问的类方法是不可调用的。因此,您必须特别检查对象是否是classmethod对象,而不是只检查它是否可调用。此解决方案产生我想要的输出:
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
元类的概念你熟悉吗?听起来你会想看看这个:也许如果你也开始使用装饰器,这个家伙:我听说过,但仅此而已。不,这看起来很有帮助。我现在正在努力让它工作,如果我能完成的话,我会在这里提供一个更新。如果我有几十个类作为父类的子类,那么我必须记住装饰每个类。我更愿意让调整方法的逻辑自动发生在\uuuu init\uuuu()
方法中。我的子类不会重写uuu init uuu(),因此在构造子类时,将始终调用父类中定义的\uuuu init uuuu()
。如果我能把类似的逻辑放在那里,那么我就会拥有我想要的功能。这就是我正在研究的内容。@JonCrowell:你可以这样做,但是\uuuu init\uuuu
是为每个实例调用的,而不是为每个类调用的,所以它似乎不是你想要的。如果您想让行为完全自动,就必须使用元类。你可以阅读元类和。我有一个类层次结构,我希望所有的方法都是类方法。多亏了你的指点,我几乎得到了我想要的。请参阅我对原始问题的编辑。我会将您的答案标记为正确。请参阅下面我的答案,它生成我想要的输出。如果您多次实例化一个类,这将导致问题,因为它将再次包装已包装的方法。至少,您应该在包装每个类时设置一个标志,将其标记为已包装。然后你可以检查开头的标志,如果类已经包装好了,就跳过包装。嗯,我想我可能搞砸了。这里给出的玩具示例给出了我想要的输出,但我的实际代码(更复杂)给了我一个令人困惑的TypeError:“NoneType”对象不可调用
消息并崩溃。您可能想发布一个新的问题。是的——即使现在我还在创建一个很好的示例来隔离这个问题。:)