【问题标题】:Getting the instance of a class decorated function获取类修饰函数的实例
【发布时间】:2021-05-07 16:29:44
【问题描述】:

我有一堂课如下:

class A:
    def __init__(self, x, y):
        self.x = x
        self.y = y

    def __call__(self, func):
        def wrapper():
            print("decorated", self.x, self.y)
            func()
        return wrapper

现在如果我想用这个类来装饰函数:

@A(4, 5)
def fn():
  print("original function")

fn()

输出:

decorated 4 5
original function

问题:

  1. 既然在@A(3, 4) 中调用了__init__ 类的构造函数,那么创建的类A 的实例到哪里去了?有没有办法引用它?

  2. 如何在不调用fn() 的情况下访问类外的属性self.x, self.y? (我想要fn.xfn.y 之类的东西,但它们不起作用)

【问题讨论】:

    标签: python function class object decorator


    【解决方案1】:

    您可以使用__closure__ 获取cell 对象的元组。

    在这种情况下,第一个元素是函数的单元对象,第二个元素是类A 的单元对象。

    您可以使用f.__closure__[1] 访问它并使用.cell_contents 获取对象。

    class A:
        def __init__(self, x, y):
            self.x = x
            self.y = y
    
        def __call__(self, func):
            def wrapper():
                print("decorated", self.x, self.y)
                func()
            return wrapper
    
    @A(1, 2)
    def f():
        print('fun')
    
    
    A_cell = f.__closure__[1]
    
    A_obj = A_cell.cell_contents
    
    print(A_obj.x, A_obj.y) # 1 2
    

    回答你的问题

    1. 有没有办法引用类A 创建的实例?是的,A_obj = f.__closure__[1].cell_contents
    2. 如何在课堂外访问属性self.xself.yA_obj.x, A_obj.y

    如果您使用的是 Python 3.8+,则可以使用 := 并避免使用 dunders 和单元格。

    你可以这样装饰

    @(a := A(1, 2)) # this assigns the object to `a`
    def f():
        print('fun')
    
    print(a is f.__closure__[1].cell_contents) # True
    

    差不多就是这个

    a=A(1, 2)
    
    @a
    def f():
        print('fun')
    

    【讨论】:

      【解决方案2】:

      你可以直接在函数上设置属性,如果你喜欢:

      class A:
          def __init__(self, x, y):
              self.x = x
              self.y = y
      
          def __call__(self, func):
              def wrapper():
                  print("decorated", self.x, self.y)
                  func()
              wrapper.x = self.x
              wrapper.y = self.y
              wrapper.decorator = self
              return wrapper
      
      @A(4, 5)
      def fn():
          pass
      
      print(fn.x, fn.y, fn.decorator)
      

      给出输出:

      laurel% python3 ~/tmp/dec.py
      4 5 <__main__.A object at 0x7f79ebb2cfd0>
      laurel% 
      

      【讨论】:

        猜你喜欢
        • 2014-12-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-11-20
        • 2020-02-03
        • 2019-02-01
        • 2020-07-30
        • 1970-01-01
        相关资源
        最近更新 更多