python装饰器4【两个参数】【wraps】【不常规套路】

  1. 代码

#  wraps的参数是原来的函数,修饰返回的函数

def _implicit_lookup(self, subroutine, arg_name):  # feed 里面查找 animal

    replacer = ArgumentReplacer(subroutine, arg_name)

    @wraps(subroutine)  # 换汤不换药,不认识了subroutine
    def lookup_closure(*args, **kwargs):
        with replacer.replace_and_call(args, kwargs) as replaced:    # 【注意】不是*args, **kwargs
            if self._should_be_replaced(replaced.value):
                self._lookup_in_store_and_replace_argument(replaced)
        return replaced.returned_value
    return lookup_closure
  1. 对比
def a_new_decorator(a_func):
    
    @wraps(a_func)
    def wrapTheFunction(*args, **kwargs):
        print("I am doing some boring work before executing a_func()")

        a_func(*args, **kwargs)   # 【注意】不是 a_func(args, kwargs)
 
        print("I am doing some boring work after executing a_func()")
 
    return wrapTheFunction


  1. 另一个不常见
https://github.com/edgedb/edgedb/blob/master/edb/common/value_dispatch.py

import functools

def value_dispatch(func):
    """Like singledispatch() but dispatches by value of the first arg.
    Example:
      @value_dispatch
      def eat(fruit):
          return f"I don't want a {fruit}..."
      @eat.register('apple')
      def _eat_apple(fruit):
          return "I love apples!"
      @eat.register('eggplant')
      @eat.register('squash')
      def _eat_what(fruit):
          return f"I didn't know {fruit} is a fruit!"
    An alternative to applying multuple `register` decorators is to
    use the `register_for_all` helper:
      @eat.register_for_all({'eggplant', 'squash'})
      def _eat_what(fruit):
          return f"I didn't know {fruit} is a fruit!"
    """

    registry = {}

    @functools.wraps(func)
    def wrapper(arg0, *args, **kwargs):
        try:
            delegate = registry[arg0]
        except KeyError:
            pass
        else:
            return delegate(arg0, *args, **kwargs)

        return func(arg0, *args, **kwargs)

    def register(value):
        def wrap(func):
            if value in registry:
                raise ValueError(
                    f'@value_dispatch: there is already a handler '
                    f'registered for {value!r}'
                )
            registry[value] = func
            return func
        return wrap

    wrapper.register = register

    return wrapper


@value_dispatch
def eat(fruit):
    return f"I don't want a {fruit}..."


@eat.register('apple')
def _eat_apple(fruit):
    return "I love apples!"


@eat.register('eggplant')
@eat.register('squash')
def _eat_what(fruit):
    return f"I didn't know {fruit} is a fruit!"

res = _eat_apple('eggplant')
print(res)
posted @ 2021-07-20 17:20  该显示昵称已被使用了  阅读(163)  评论(0编辑  收藏  举报