代码之家  ›  专栏  ›  技术社区  ›  Nick Chapman

Python-将类作为参数传递给该类中方法的装饰器?

  •  3
  • Nick Chapman  · 技术社区  · 7 年前

    我希望做以下工作:

    class A(object):
        def first_method(self):
            print "I'm the first method!"    
    
        @some_decorator(A.first_method)
        def second_method(self):
            print "I'm the second method!"
    

    但我遇到了一个问题 A 在解析装饰器时,在其自身中未定义。有什么方法可以让我参考吗 A. 在装饰店?或者,如果我只是将绑定方法传递给decorator first_method first_方法 属于 A.

    2 回复  |  直到 7 年前
        1
  •  2
  •   Sergey Vasilyev    7 年前

    在python 3中,您可以说 @some_decorator(first_method)

    在python 2中,有一个复杂的绑定系统&未绑定、实例、类和静态方法。因此,您无法访问 first_method 在类定义m内(直到类完全形成)。

    一个小的解决方法是将该类分为两个类:

    class BaseA(object):
        def first_method(self):
            print "I'm the first method!"    
    
    class A(BaseA):
        @some_decorator(BaseA.first_method)
        def second_method(self):
            print "I'm the second method!"
    

    不是所有情况下的最佳解决方案,但会奏效。


    此外,请记住,在这两种情况下(py2和py3),装饰器都会引用 正如这里宣布的那样。如果任何子类重新定义了该方法,则新方法将不会在装饰器中使用;只使用父对象。

    first_方法 self / cls 装饰器包装中的第一个位置参数,并使用 self.first_method / cls.first_method

    import functools
    
    def some_decorator(fn):
        @functools.wraps(fn)
        def wrapper(self, *args, **kwargs):
            first_method = self.first_method
            first_method()
            return fn(self, *args, **kwargs)
        return wrapper
    
    class A(object):
        def first_method(self):
            print "I'm the first method of A!"    
    
        @some_decorator
        def second_method(self):
            print "I'm the second method!"
    
    
    class B(A):
        def first_method(self):
            print "I'm the first method of B!"    
    
    
    A().second_method()
    # I'm the first method of A!
    # I'm the second method!
    
    B().second_method()
    # I'm the first method of B!
    # I'm the second method!
    

    如果要使该方法可配置:

    def some_decorator(method_name):
        def decorator(fn):
            @functools.wraps(fn)
            def wrapper(self, *args, **kwargs):
                first_method = getattr(self, method_name)
                first_method()
                return fn(self, *args, **kwargs)
            return wrapper
        return decorator
    
    
    class A(object):
        def first_method(self):
            print "I'm the first method of A!"    
    
        @some_decorator('first_method')
        def second_method(self):
            print "I'm the second method!"
    
    class B(A):
        def first_method(self):
            print "I'm the first method of B!"    
    
        2
  •  0
  •   Laurent LAPORTE    7 年前

    def some_decorator(arg):
        # ...
        pass
    
    
    class A(object):
        def first_method(self):
            print("I'm the first method!")
    
        def second_method(self):
            print("I'm the second method!")
    
    
    A.second_method = some_decorator(A.first_method)(A.second_method)