Python – 我可以以编程方式从类实例中修饰类方法吗?

我有一个对象层次结构,其中几乎所有方法都是类方法.它看起来如下:

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’对象不可调用).相反,我希望每个方法的装饰以编程方式在__init __()方法中进行.

是否有可能以编程方式在Python中修饰方法?

编辑:发现似乎有用的东西 – 请参阅下面的答案.感谢BrenBarn.

解决方法:

所有装饰器都会返回一个新函数.这个:

@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对象,而不是只检查它是否可调用.

上一篇:python – 如何修改类__dict__(mappingproxy)?


下一篇:我两次包装I / O流时会发生什么?