用于编写简单装饰器的工具。
Decorum的Python项目详细描述
礼仪是一个图书馆,旨在使它更容易写灵活和简单。 装饰工:
- 像你需要的那样使用decorators:不要用括号,pass 当你需要的时候。
- 像您所想的那样编写装饰器:它们可以初始化,也可以不初始化 选项,它们包装一个函数,它们是可调用的。
- 测试装潢师:真的很容易,你没有借口!
因循守旧
为了编写自己的decorators,只需子类decorum.Decorum:
>>> fromdecorumimportDecorum>>> classempty_decorator(Decorum):... """Just inherit from Decorum's builtins."""
当然你会想定制装饰的行为!只有 需要注意的三种方法:
- init()设置装饰器本身;
- wraps()修饰函数;
- call()运行包装函数并返回结果。
这里有一个简单的装饰器来演示礼仪用法:
>>> from__future__importprint_function>>> classverbose_decorator(Decorum):... """Print info about decoration process."""... definit(self,*args,**kwargs):... print('Initializing decorator with args={} and kwargs={}'... .format(args,kwargs))... returnsuper(verbose_decorator,self).init(*args,**kwargs)...... defwraps(self,f):... print('Wrapping function "{}"'.format(f.__name__))... returnsuper(verbose_decorator,self).wraps(f)...... defcall(self,*args,**kwargs):... print('Running wrapped function with args={} and kwargs={}'... .format(args,kwargs))... returnsuper(verbose_decorator,self).call(*args,**kwargs)
然后您可以将其用作任何装饰:
>>> @verbose_decorator... deffoo(x):... print(x)Initializing decorator with args=() and kwargs={} Wrapping function "foo" >>> foo('bar')Running wrapped function with args=('bar',) and kwargs={} bar
注意
您还可以使用decorum.decorator将类转换为装饰器。
>>> fromdecorumimportdecorator>>> @decorator... classnoop:... """Override init(), wraps() or call() if you like.""">>> @noop... deffoo():... """Do nothing."""
其结果是一个继承自原始类和礼仪的类:
>>> isinstance(foo,noop)True >>> isinstance(foo,Decorum)True
不用麻烦用括号
礼仪允许您以统一的方式编写带参数和不带参数的装饰器。 那么您的decorator可以使用有无参数,调用与否,以及 它将以同样的方式工作:
>>> @verbose_decorator... deffoo(x):... print(x)Initializing decorator with args=() and kwargs={} Wrapping function "foo"
与:
>>> @verbose_decorator()... deffoo(x):... print(x)Initializing decorator with args=() and kwargs={} Wrapping function "foo"
使用选项初始化装饰器
要实现接受自定义选项的decorator,只需更改init():
>>> classconfigurable_decorator(Decorum):... definit(self,custom_option='default',*args,**kwargs):... print('Initializing decorator with custom_option="{}"'... .format(custom_option))... # Remember the option, typically for use in wraps() or call().... self.custom_option=custom_option... # Call super().init() with remaining arguments.... returnsuper(configurable_decorator,self).init(*args,**kwargs)
当我们使用关键字参数时,它是可选的:
>>> @configurable_decorator... deffoo(x):... print(x)Initializing decorator with custom_option="default" >>> foo.custom_option'default'
我们可以在修饰函数时传递这个选项。或者作为位置 参数…
>>> @configurable_decorator('positional')... deffoo(x):... print(x)Initializing decorator with custom_option="positional" >>> foo.custom_option'positional'
…或关键字参数:
>>> @configurable_decorator(custom_option='keyword')... deffoo(x):... print(x)Initializing decorator with custom_option="keyword" >>> foo.custom_option'keyword'
当然,不能传递未声明为^{tt2}的参数$ 选项:
>>> @configurable_decorator(wrong_option=True)# doctest: +ELLIPSIS... deffoo(x):... print(x)Traceback (most recent call last): ...TypeError: init() got an unexpected keyword argument 'wrong_option'
注意
在大多数情况下,init()应该接受额外的参数和代理 通过super(...).init(*args, **kwargs)将它们设置为父级。这边,选项 支持的祖先类。
例如,Decorum基类声明了assigned关键字参数 在init()中(请参阅下面的wrap function部分)。
包装功能
wraps()方法允许您处理修饰的函数。它收到 将修饰为单个位置参数并返回可调用的 (通常是self)。
在大多数情况下,wraps()函数将return super(...,self).wraps(f)。
默认情况下,基Decorum.wraps()将尝试保持assign 属性,即__doc__和 __name__。此功能使用functools.wraps。
>>> classidentity(Decorum):... """Noop decorator: does nothing!""">>> @identity... defmy_function():... """My function's docstring.""">>> print(my_function.__name__)my_function >>> print(my_function.__doc__)My function's docstring.
可选的assigned关键字参数可用于指定 原始函数的属性直接分配给匹配 包装器函数的属性。默认为 functools.WRAPPER_ASSIGNMENTS。您可以将False或None指定为 禁用此。
>>> @identity(assigned=None)... defmy_function():... """My function's docstring.""">>> print(my_function.__name__)identity >>> print(my_function.__doc__)Noop decorator: does nothing!
运行修饰函数
Decorum.call()方法接收*args和**kwargs作为输入。它运行 包装的函数,并返回结果。
下面是一个简单的decorator,它重复decorated函数的结果:
>>> classrepeat(Decorum):... defcall(self,*args,**kwargs):... result=super(repeat,self).call(*args,**kwargs)... return' '.join([result]*2)>>> @repeat... defparrot(word):... returnword>>> parrot('hello')'hello hello'
测试装饰器
礼节使测试自定义装饰器变得容易。
断言装饰器具有预期的行为
decorators被定义为类,因此您可以对 你来测试。你的测试可以集中在你定制的东西上。
让我们检查前面部分中的repeatdecorator。因为我们只是 重写call(),让我们关注它:
>>> decorator=repeat(lambdax:x.upper())>>> result=decorator.call('input')>>> assertresult=='INPUT INPUT'
这对单元测试装饰器非常有用。
断言函数已被修饰
decorator是Decorum或子类的实例。所以你可以检查 装饰性功能。
让我们从上面的示例中检查my_function:
>>> assertisinstance(my_function,Decorum)>>> assertisinstance(my_function,identity)
知道n限制
礼仪有一些鲜为人知的局限性:
- 装饰程序的init()不能接收单个位置参数 是一个可呼叫的。礼节将尝试触发器wraps(),而不是init()。 这样的案子。
关于
礼仪项目是自由软件,在麻省理工学院许可下发布。