代码之家  ›  专栏  ›  技术社区  ›  J S

如何使用类实例变量作为Python中方法装饰器的参数?

  •  5
  • J S  · 技术社区  · 17 年前

    如何使用类实例变量作为Python中方法装饰器的参数? 下面是一个简单的例子,展示了我正在尝试做的事情。它显然失败了,因为decorator函数没有访问实例引用的权限,我不知道如何从decorator访问引用。

    def decorator1(arg1):
        def wrapper(function):
            print "decorator argument: %s" % arg1
            return function
        return wrapper
    
    class Foo(object):
        def __init__(self, arg1):
            self.var1 = arg1
    
        @decorator1(self.var1)
        def method1(self):
            print "method1"
    
    foo = Foo("abc")
    foo.method1()
    
    4 回复  |  直到 17 年前
        1
  •  11
  •   balpha    17 年前

    这是行不通的;装修工在装修期间被叫来 类创建 时间,在创建实例之前很长时间( 这永远不会发生)。因此,如果您的“装饰者”需要实例,您必须在实例化时进行“装饰”:

    def get_decorator(arg1):
        def my_decorator(function):
            print "get_decorator argument: %s" % arg1
            return function
        return my_decorator
    
    class Foo(object):
        def __init__(self, arg1):
            self.var1 = arg1
            self.method1 = get_decorator(self.var1)(self.method1)
    
        def method1(self):
            print "method1"
    
    foo = Foo("abc")
    foo.method1()
    

    注意,我根据函数名的含义更改了它们;实际的“decorator”,即(可能)修改方法的函数是 wrapper 就你而言,不是 decorator1

        2
  •  8
  •   Arpegius    17 年前

    def decorator(function):
      def wrapper(self,*args,**kwargs):
        print "Doing something with self.var1==%s" % self.var1
        return function(self,*args,**kwargs)
      return wrapper
    
    class Foo(object):
      def __init__(self, arg1):
        self.var1 = arg1
    
      @decorator
      def method1(self):
        print "method1"
    
    foo = Foo("abc")
    foo.method1()
    

    class decorator:
      def __init__(self,varname):
          self.varname = varname
      def __call__(self,function):
        varname=self.varname
        def wrapper(self,*args,**kwargs):
          print "Doing something with self.%s==%s" % (varname,getattr(self,varname))
          return function(self,*args,**kwargs)
        return wrapper
    

    使用:

      @decorator("var1")
    
        3
  •  1
  •   S.Lott    17 年前

    这是我们过去的做法。

    class Foo(object):
        def __init__(self, arg1):
            self.var1 = arg1
    
        def method1(self):
            self.lock()
            try:
                self.do_method1()
            except Exception:
                pass # Might want to log this
            finally:
                self.unlock()
    
        def do_method1(self):
            print "method1"
    
        def lock(self):
            print "locking: %s" % self.arg1
    
        def unlock(self):
            print "unlocking: %s" % self.arg1
    

    现在,子类只需要o重写 do_method1 以获得“包装”的好处。按老办法做,没有任何问题 with 陈述

        4
  •  1
  •   mosegui    7 年前

    您正试图在类创建时使用仅在实例化时可用的信息构造包装器。您可以在实例化时动态地构建decorator,但仍然需要将decorator应用于方法的外部类级别无法访问实例变量。

    为了避免使用decorator解决这个问题所带来的混乱,Python(从2.7开始)合并了一个专用的数据模型来解决这个特定类型的问题。它被称为 context manager

    from contextlib import contextmanager
    
    def lock_file(file):
        print('File %s locked' % file)
    
    def unlock_file(file):
        print('File %s unlocked' % file)
    
    @contextmanager
    def file_locked(arg1):
        lock_file(arg1)
        yield
        unlock_file(arg1)
    
    class Foo(object):
        def __init__(self, arg1):
            self.var1 = arg1
    
        def method1(self):
            with file_locked(self.var1) as f:
                print "method1"
    
    foo = Foo("abc")
    foo.method1()
    
        5
  •  0
  •   UncleZeiv    17 年前

        6
  •  0
  •   Kiran Kumar Kotari    5 年前

    嵌套方法成功了,我在使用self时遇到了再次传递self的问题。后来,我用lambda包装函数赋值来解决这个问题。

    https://gist.github.com/kirankotari/e6959e74316352bfd06afa4d5ab8bd52