Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/317.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python装饰器3.0和装饰器的参数_Python_Decorator - Fatal编程技术网

Python装饰器3.0和装饰器的参数

Python装饰器3.0和装饰器的参数,python,decorator,Python,Decorator,我很高兴看到最新版本的decoratorpython模块(3.0)。它看起来比以前的迭代更干净(例如,语法比以往任何时候都更甜) 然而,它似乎对自己接受参数的装饰器的支持很差(例如,用“sour”语法来可怕地扩展隐喻)。有没有人能举一个很好的例子来说明如何使用decorator3.0干净地做到这一点 def substitute_args(fun, arg_sub_dict): def wrapper(arg): new_arg = arg_sub_dict.ge

我很高兴看到最新版本的
decorator
python模块(3.0)。它看起来比以前的迭代更干净(例如,语法比以往任何时候都更甜)

然而,它似乎对自己接受参数的装饰器的支持很差(例如,用“sour”语法来可怕地扩展隐喻)。有没有人能举一个很好的例子来说明如何使用
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

在这种情况下,您需要使函数返回decorator。(任何事情都可以通过另一个间接层次解决…)

这意味着
substitute\u args
本身不是装饰器,而是装饰器工厂。这里是没有
装饰器
模块的等价物

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.wrapps修饰以保留名称和文档字符串)

在另一种情况下,应存在一个或多个命名或位置参数;您可以收集这些参数并返回一个callable,该callable接受一个callable作为第一个参数并返回一个包装器方法,因为该描述符合decorator方法的描述,所以返回该decorator方法!我使用了
functools.partial
在这里获得了我的装饰器的一个版本,
是\u global\u method
(我现在正在研究它的实现,它的实现当然毫无意义,如下所示,这只是为了演示装饰工作)

这个解决方案似乎可行,但确实需要更多的测试。如果你仔细观察我们的眼睛,你会发现这个把戏只有三到四条线作为记忆的模式。现在我想知道是否可以将这种功能包装到另一个装饰器中?啊,它的元性

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 ) )
装饰家:
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 ) )