用于编写简单装饰器的工具。

Decorum的Python项目详细描述


https://travis-ci.org/zeekay/decorum.png?branch=master

礼仪是一个图书馆,旨在使它更容易写灵活和简单。 装饰工:

  • 像你需要的那样使用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。您可以将FalseNone指定为 禁用此。

>>> @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()。 这样的案子。

关于

礼仪项目是自由软件,在麻省理工学院许可下发布。

欢迎加入QQ群-->: 979659372 Python中文网_新手群

推荐PyPI第三方库


热门话题
java需要一种简单的方法来创建用于排序的comparator类   java getReadableDatabase和getWriteableDatabase无法解析   查找列表<Long>中与某个元素对应的所有索引的java方法   安卓将视图添加到ViewFlipper会导致java。StackOverflowerr语言   java根据它所包含的长“curTime”类字段将N的列表拆分为24(小时)   Android N中的Java8流API   自动生成Java策略文件的安全性   垃圾收集鼓励Java中的主要GC(但不是STW GC)   java如何检查UDP服务器上侦听的客户端数量   在前一台主机被Datastax Java驱动程序关闭后,Cassandra尝试重新连接到下一台主机   java如何使用Spring Boot创建部分代理   java是否有一个网站或资源可以完全比较EJB版本   java无需使用第三方库从gradle生成输出   继承由于这个多态性的基本示例中的语法有什么不同吗?(爪哇)   java字符串数组中的空字符串   java为什么CMS中的初始标记阶段是串行的   为什么Lucene有时与InChIKeys不匹配?   安卓通知Java应用程序数据库中的更改   java如何将单个json对象值解析为按钮   java打印堆栈将运行时错误跟踪到文件