【问题标题】:Python decorators with instance level information [duplicate]具有实例级信息的 Python 装饰器 [重复]
【发布时间】:2017-07-26 12:34:11
【问题描述】:

所以下面是一个无效的例子,说明了我想要达到的目的

class TestClass(object):

    def require_debug_mode(self, f):
        def func_wrapper(*args, **kwargs):
            if self.debug_mode:
                return f(*args, **kwargs)
        return func_wrapper

    def __init__(self, debug_mode):
        self.debug_mode = debug_mode

    @require_debug_mode
    def print_message(self, msg):
        print msg

您可以重写所需的print_message,如下所示:

def print_message(self, msg):
    if self.debug_mode:
        print msg

我本质上希望能够装饰将执行某些检查的方法(不必在每个可能使用它的方法中重复该检查)。但是这些检查需要访问实例级别的信息。这可能吗?

【问题讨论】:

  • 是的,这很容易实现。您刚刚将self 参数放在错误的位置。 inner 函数需要self 参数。

标签: python decorator


【解决方案1】:

要将装饰器作为类的一部分,您可以使用以下代码:

class TestClass(object):

    def require_debug_mode(f):
        def func_wrapper(self, *args, **kwargs):
            if self.debug_mode:
                return f(self, *args)
        return func_wrapper

    def __init__(self, debug_mode):
        self.debug_mode = debug_mode

    @require_debug_mode
    def print_message(self, msg):
        print(msg)

tc_obj = TestClass(True)
tc_obj.print_message("debug msg")
# debug msg

tc_obj = TestClass(False)
tc_obj.print_message("debug msg")
# no output

要将装饰器保持在类之外,您可以使用以下方法

def require_debug_mode(f):
    def wrapper(*args):
        if args[0].debug_mode:
            return f(*args)
    return wrapper

class TestClass(object):
    def __init__(self, debug_mode):
        self.debug_mode = debug_mode

    @require_debug_mode
    def print_message(self, msg):
        print(msg)

tc_obj = TestClass(True)
tc_obj.print_message("debug msg")
# debug msg

tc_obj = TestClass(False)
tc_obj.print_message("debug msg")
# no output

【讨论】:

    【解决方案2】:

    装饰器是一个函数,给定一个函数作为输入,返回一个函数作为输出。

    您想将函数print_message(self, msg) 作为输入。没关系。

    为了使装饰器有效地工作,生成的函数必须具有相似的行为。所以你想包装这个函数,解码足够多的参数来让“偷看”看到你想要的东西:

    def func_wrapper(self, *args, **kwargs):
        if self.debug_mode:
            return self.f(*args, **kwargs)
    

    【讨论】:

      【解决方案3】:

      装饰器接收与常规方法相同的参数,这意味着 self 也可用于装饰器。您的代码的问题是您希望外部包装器也能获得 self 参数,但事实并非如此(它在声明时调用,此时没有实例)。

      例如:

      import functools
      
      
      class TestClass(object):
      
          def require_debug_mode(function):
      
              @functools.wraps(function)
              def _require_debug_mode(self, *args, **kwargs):
                  assert self.debug_mode, 'Debug mode is required for %r' % function
                  return function(self, *args, **kwargs)
      
              return _require_debug_mode
      
          def __init__(self, debug_mode):
              self.debug_mode = debug_mode
      
          @require_debug_mode
          def print_message(self, msg):
              print msg
      
      
      test_class = TestClass(True)
      test_class.print_message('ping')
      
      test_class = TestClass(False)
      test_class.print_message('pong')
      

      输出:

      ping
      Traceback (most recent call last):
          ...
      AssertionError: Debug mode is required for <function print_message at 0x...>
      shell returned 1
      

      【讨论】:

        猜你喜欢
        • 2015-06-24
        • 2020-07-08
        • 1970-01-01
        • 1970-01-01
        • 2013-02-18
        • 2021-10-10
        • 2013-02-12
        • 2011-05-24
        • 2012-02-09
        相关资源
        最近更新 更多