【问题标题】:Why is partial used to add attributes to functions为什么要使用partial给函数添加属性
【发布时间】:2020-06-21 19:58:03
【问题描述】:

前几天看了this的文章,不明白为什么在“Logging Decorators”部分使用partial

def attach_wrapper(obj, func=None):  # Helper function that attaches function as attribute of an object
    if func is None:
        return partial(attach_wrapper, obj)
    setattr(obj, func.__name__, func)
    return func

attach_wrapper 未设置用于包装另一个函数的函数的某些属性:

@attach_wrapper(wrapper)  # Attaches "set_level" to "wrapper" as attribute
def set_level(new_level):  # Function that allows us to set log level
    nonlocal level
    level = new_level

为什么不能在wrappersetattr 上直接设置这些属性?

【问题讨论】:

    标签: python python-decorators


    【解决方案1】:

    它的用途是,如果在没有要包装的函数的情况下调用 attach_wrapper 函数,它将返回一些内容,然后您可以使用其他函数调用这些内容以将多个附加到目标对象。例如,如果您有三个函数fgh,以及一个对象foo,您可以使用attach_to_foo = attach_wrapper(foo) 创建一个“附加器”,然后将它与attach_to_foo(f)、@987654328 一起使用@ 和 attach_to_foo(h)foo.ffoo.gfoo.h 结尾。

    【讨论】:

      【解决方案2】:

      如果您检测attach_wrapper,您可以看到它的func 参数是None

      def attach_wrapper(obj, func=None):  # Helper function that attaches function as attribute of an object
          if func is None:
              print(f'obj is {obj.__name__} - func is',func)
              return partial(attach_wrapper, obj)
          print(f'a_w:obj is {obj.__name__} - func is {func.__name__}')
          setattr(obj, func.__name__, func)
          return func
      

      然后

      @log(logging.WARN, "example-param")
      def somefunc(args):
          return args
      

      结果

      >>>
      obj is somefunc - func is None
      a_w:obj is somefunc - func is set_level
      obj is somefunc - func is None
      a_w:obj is somefunc - func is set_message
      >>>
      

      attach_wrapper 被调用两次。第一次它的funcNone,它返回一个带有第一个参数obj 的部分函数attach_wrapper 设置为 some_func。然后调用部分函数(装饰器机制的所有部分)并装饰函数。

      attach_wrapper's obj 看起来像 some_func 但实际上是 some_func 包裹 wrapper - 看起来和感觉都一样,因为这就是 @wraps 的用途.


      这里是更多细节,将inspect.stack 添加到instrumentation

      import inspect
      
      def attach_wrapper(obj, func=None):  # Helper function that attaches function as attribute of an object
          print("called from: ", inspect.stack()[1].code_context[0].strip())
          print("\tby function ", inspect.stack()[1].function)
          if func is None:
              print(f'\tobj is {obj.__name__}, func is {func}\n')
              return partial(attach_wrapper, obj)
          print(f'\tobj is {obj.__name__}, func is {func.__name__}\n')
          setattr(obj, func.__name__, func)
          return func
      

      哪个产生

      >>>
      called from:  @attach_wrapper(wrapper)  # Attaches "set_level" to "wrapper" as attribute
          by function  decorate
          obj is somefunc, func is None
      
      called from:  def set_level(new_level):  # Function that allows us to set log level
          by function  decorate
          obj is somefunc, func is set_level
      
      called from:  @attach_wrapper(wrapper)  # Attaches "set_message" to "wrapper" as attribute
          by function  decorate
          obj is somefunc, func is None
      
      called from:  def set_message(new_message):  # Function that allows us to set message
          by function  decorate
          obj is somefunc, func is set_message
      
      >>>
      

      周围有一些更好的详细解释。如果我找到了,我会更新。

      【讨论】:

        猜你喜欢
        • 2013-03-13
        • 1970-01-01
        • 2011-03-20
        • 2013-08-17
        • 2017-04-20
        • 1970-01-01
        • 2018-11-04
        • 2010-11-28
        • 1970-01-01
        相关资源
        最近更新 更多