【问题标题】:How to decorate all methods in a class? Can I just decorate the class? [duplicate]如何装饰类中的所有方法?我可以装饰班级吗? [复制]
【发布时间】:2014-06-07 02:39:21
【问题描述】:

我有几个类,它们具有相同的实现名称但实现不同。我想装饰某些类中的所有方法,但另一些则不。我想过继承,但是有些类有一些方法不需要修饰。问题是我不想一个个装饰方法,有些类需要同一个装饰器装饰,有没有解决办法解决?

【问题讨论】:

  • 请重新格式化您的问题并澄清以下几点:“但有些类的方法不需要装饰”反对“我想装饰类中的所有方法” - 这听起来像是一个悖论,而且有很多语法错误。
  • 感谢您的提醒。问题是我不想一一装饰方法,有些类需要同一个装饰器来装饰
  • 你知道你可以在整个类中使用装饰器吗? @decorator; class A(object): ...
  • 我不知道,我只是装饰器可以将类作为参数,有没有使用装饰器和类的例子?

标签: python


【解决方案1】:

您可以启动所有需要用一些前缀装饰的方法,然后使用如下内容:

class Xobject(object):

    def __init__(self, decorator):
        for method_name in dir(self):
            if method_name.startswith("dec_"):
                attr = getattr(self, method_name)
                wrapped = decorator(attr)
                setattr(self, method_name, wrapped)

    def dec_me_1(self):
        print("In dec_me1")
        return 0

    def dec_me_2(self):
        print("In dec_me2")
        return 1


def decorator(func):

    def wrapped(*args):
        print("TEST")
        return func(*args)

    return wrapped


x = Xobject(decorator)

x.dec_me_1()
x.dec_me_2()

更新

你可以通过下面的函数来装饰类。使用 Python 时,您应该知道 Python 中的 class 也是对象,因此您可以更改它并将其传递给其他函数。

def decorator(func):

    def wrapped(*args):
        print("TEST")
        return func(*args)

    return wrapped


def decorate_object(p_object, decorator):
    for method_name in dir(p_object):
        if method_name.startswith("dec_"):
            attr = getattr(p_object, method_name)
            wrapped = decorator(attr)
            setattr(p_object, method_name, wrapped)

decorate_object(Xobject, decorator)

x = Xobject()

x.dec_me_1()
x.dec_me_2()

你也可以用同样的方式装饰已经实例化的对象:

x = Xobject()

x.dec_me_1()
x.dec_me_2()

decorate_object(x, decorator)

x.dec_me_1()
x.dec_me_2()

【讨论】:

  • 如果我的类没有 init 方法,它们实际上继承自同一个类,但我不想更改基类。
  • 可以使用单独的函数装饰以“某物”开头的类的每个方法,并将需要装饰的类或对象传递给它。我已经用示例更新了我的答案。
  • 它有效,谢谢。我知道如何解决它! :)
【解决方案2】:

我确信有几种方法可以解决这个问题,但主要的主要选择是:

  • 创建一个自定义元类,其中__new__ 方法遍历属性字典,识别方法并装饰它们。有关 Python 元类编程的示例,请参阅 http://eli.thegreenplace.net/2011/08/14/python-metaclasses-by-example/。缺点:这可能比我们想在这里更复杂。
  • 在常规类的__init__ 方法中执行相同的操作。缺点:只装饰实例方法,不装饰类或静态方法,而且速度较慢,因为每次创建新实例时都会运行。
  • 在课外做:

    class Foo(object):
      def bar(self):
        print 'bar'
    
    for name, ref in vars(Foo):
      if callable(ref): ...
    

    缺点:您只有一次机会做对:在导入时。子类不会被修改。

  • 在类级别的装饰器中进行。和课外做同样的缺点(我认为)。

【讨论】:

  • 是的,我也考虑过元类,它复杂且难以阅读,所以我可能会一一添加装饰器。谢谢
【解决方案3】:

在某些时候,您必须明确说明什么被包装,什么不被包装。

如果我的理解正确,我认为你可以这样做:

def wrapper(func):
    def inner(*args, **kwargs):
        print "%s was called" func.__name__
        return func(*args, **kwargs)
    return inner

class A(object):
    def foo(self):
        print "foo called"
    def bar(self):
        print "BAR CALLED"

class B(A):
    @wrapper
    def foo(self):
        super(B, self).foo()

class C(A):
    @wrapper
    def bar(self):
        super(C, self).bar()

Stick = A()
Dave = B()
Jupiter = C()

Jupiter.foo() #prints "foo called"
Jupiter.bar() #prints "bar wrapped" and "BAR CALLED"

【讨论】:

    猜你喜欢
    • 2016-01-13
    • 2015-08-13
    • 2010-10-15
    • 1970-01-01
    • 2011-08-10
    • 2012-02-09
    • 2019-10-02
    • 2021-03-17
    • 2014-01-14
    相关资源
    最近更新 更多