Python-我可以以编程方式装饰类实例中的类方法吗? [英] Python - can I programmatically decorate class methods from a class instance?

查看:80
本文介绍了Python-我可以以编程方式装饰类实例中的类方法吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个对象层次结构,其中几乎所有方法都是类方法。看起来像以下内容:

I have an object hierarchy in which almost all of the methods are class methods. It looks like the following:

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()

给定的代码输出以下内容:

The code as given outputs the following:

greetings
hello son
goodbye son
greetings
hello daughter
goodbye daughter

我希望代码输出以下内容:

I would like the code to output the following:

-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'ob ject不可调用)。相反,我希望每种方法的修饰都可以通过 __ init __()方法以编程方式进行。

But I don't want to add the line @smile_warmly before each method (and when I try to do that in the code above, I get error message TypeError: 'classmethod' object is not callable). Rather, I would like the decoration of each method to take place programmatically in the __init__() method.

EDIT :找到了一些行之有效的方法-请参阅下面的答案。

EDIT: Found something that seems to work -- see my answer below. Thanks to BrenBarn.

推荐答案

装饰器所做的全部工作就是返回一个新函数。

All a decorator does is return a new function. This:

@deco
def foo():
    # blah

与此相同:

def foo():
    # blah
foo = deco(foo)

您可以在不使用 @ 语法的情况下随时执行相同的操作,只需将函数替换为所需的内容即可。因此,在 __ init __ 或其他任何地方,您都可以遍历所有方法,并用 smilewarmly(meth)。

You can do the same thing whenever you like, without the @ syntax, just by replacing functions with whatever you like. So in __init__ or wherever else, you could loop through all the methods and for each one replace it with smilewarmly(meth).

但是,与其在 __ init __ 中进行操作,不如在上课时这样做被建造。您可以使用元类,或更简单地使用类装饰器来做到这一点:

However, instead of doing it in __init__, it would make more sense to do it when the class is created. You could do this with a metaclass, or more simply with a class decorator:

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

In this example I put the classmethod decoration inside my smileDeco decorator. You could also put it in makeSmiley so that makeSmiley returned smileDeco(classmethod(val)). (Which way you want to do it depends on how closely linked the smile-decorator is to the things being classmethods.) This means you don't have to use @classmethod inside the class.

当然,在 makeSmiley 的循环中,您可以包括任何您想要决定的逻辑(例如,基于该方法的名称)是否用微笑行为将其包装。

Also, of course, in the loop in makeSmiley you can include whatever logic you like to decide (for instance, based on the method's name) whether to wrap it with the smile behavior or not.

请注意,如果您必须谨慎一点我真的想在类中手动使用 @classmethod ,因为通过类 __ dict __ 访问的类方法是不可调用的。因此,您必须专门检查该对象是否为类方法对象,而不仅仅是检查它是否可调用。

Note that you'd have to be a little more careful if you really want to manually use @classmethod inside the class, because classmethods as accessed via the class __dict__ aren't callable. So you'd have to specifically check whether the object is a classmethod object, instead of just checking whether it's callable.

这篇关于Python-我可以以编程方式装饰类实例中的类方法吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆