我很高兴见到最新版本的decorator蟒模块(3.0)的。它看起来非常清洁器(例如,语法是比以往更含糖)比以前的迭代。

然而,似乎有糟糕的载体(例如“酸”的语法,以可怕拉伸比喻),用于带参数本身的装饰。有没有人有多么你会清晰地做到这一点使用decorator 3.0个很好的例子?

 def substitute_args(fun, arg_sub_dict):
      def wrapper(arg):
         new_arg = arg_sub_dict.get(arg, arg)
         return fun(new_arg)

      # some magic happens here to make sure that type signature, 
      # __name__, __doc__, etc. of wrapper matches fun

 return wrapper
有帮助吗?

解决方案

在这种情况下,你需要让你的函数返回的装饰。 (什么都可以通过间接的另一个电平来解决...)

from decorator import decorator
def substitute_args(arg_sub_dict):
  @decorator
  def wrapper(fun, arg):
    new_arg = arg_sub_dict.get(arg, arg)
    return fun(new_arg)
  return wrapper

这意味着substitute_args不是一个装饰本身,这是一个装饰工厂。这里的无decorator模块等效。

def substitute_args(arg_sub_dict):
  def my_decorator(fun):
    def wrapper(arg):
      new_arg = arg_sub_dict.get(arg, arg)
      return fun(new_arg)
    # magic to update __name__, etc.
    return wrapper
  return my_decorator

三个层次深不是很方便,但要记住其中两个是当函数定义:

@substitute_args({}) # this function is called and return value is the decorator
def f(x):
  return x
# that (anonymous) decorator is applied to f

即相当于:

def f(x):
  return x
f = substitude_args({})(f) # notice the double call

其他提示

这里是另一种方式,我刚刚发现:检查第一个(也是唯一的)参数你的装饰是否可赎回;如果是这样,你完成,并且可以返回自己的行为,修改包装方法(本身functools.wraps装饰,以保留名称和文档字符串)。

在另一种情况下,一个或多个命名或位置参数应该存在;你可以收集这些参数,并返回一个接受调用作为第一个参数和返回的包装方法,并自认为适合描述装饰方法的描述可赎回,回报非常装饰方法!我用functools.partial这里得到一个版本我的装饰,is_global_method的(这我的工作,现在,它的实现当然是无稽之谈,如下图所示,这只是证明装饰装修工程)。

这个解决方案似乎工作,但肯定需要更多的测试。如果你昆特我们的眼睛,你可以看到,关键是只有三,四线的模式记忆。现在我不知道我是否可以换那种功能集成到另一个设计师吗?啊,它的metaness!

from functools import wraps
from functools import partial

_               = print
is_instance_of  = isinstance
is_callable     = lambda x: hasattr( x, '__call__' )

def is_global_method( x, *, name = None ):
  if is_callable( x ):
    @wraps( x )
    def wrapper( *P, **Q ):
      return { 'name': name, 'result': x( *P, **Q ), }
    return wrapper
  # assert is_instance_of( x, str ) # could do some sanity checks here
  return partial( is_global_method, name = x )

@is_global_method
def f( x ):
  """This is method f."""
  return x ** 2

@is_global_method( 'foobar' )
def g( x ):
  """This is method g."""
  return x ** 2

_( f.__name__ )
_( f.__doc__ )
_( f( 42 ) )
_( g.__name__ )
_( g.__doc__ )
_( g( 42 ) )
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top