不过,使用可选参数制作包装器的简单实用工具

biwrap的Python项目详细描述


不过,使用简单的实用工具制作带有可选参数的包装器

安装

主分支

pip install git+https://github.com/ferrine/biwrap

最新版本

pip install biwrap

概述的问题

可读性和透明实现非常重要。包装器是编程中的高级主题,在某些情况下使它们可读是困难的。特殊情况是参数化包装。可以使用参数调用它,也可以不使用参数调用它。处理这种情况的实现通常很复杂,看起来很奇怪(请参见SO thread)。这个包解决了这个问题,并提供了简单通用的解决方案。

API

将其应用于问题的最小片段。

importbiwrap@biwrap.biwrapdefwrapper(fn,arg1='default',arg2='default'):defwrapped(*fn_args,**fn_kwargs):...# depends on `arg1`, `arg2`returnwrapped@wrapper# use defaultsdeffunc1(a,b):...@wrapper(arg1='non default')# change defaultsdeffunc2(a,b):...

示例

让我们讨论一个需要将函数放入注册表的情况。有些函数可以有别名。

天真的解决方案

defregister(alias=None):definner(fn):iffn.__name__notinregister.storage:register.storage[fn.__name__]=fnelifregister.storage[fn.__name__]isnotfn:raiseKeyError('{} is already in storage'.format(fn.__name__))ifaliasisnotNoneandaliasnotinregister.storage:register.storage[alias]=fnelifaliasisnotNone:raiseKeyError('{} is already in storage'.format(alias))returnfnreturninnerregister.storage={}@register()deff1(a):returnaprint(register.storage)#> {'f1': <function f1 at 0x11ff519d8>}@register(alias='fn3')deff2(a):returnaprint(register.storage)#> {'f1': <function f1 at 0x11ff519d8>, 'f2': <function f2 at 0x10a87d0d0>, 'fn3': <function f2 at 0x10a87d0d0>}

分析

上面的示例在

  • decorator定义具有双嵌套(doubledef
  • 用法需要后面的括号@register(),即使我们不使用可选参数

更具可读性的代码应该避免这两点,并且看起来像:

defregister(fn,alias=None):...@registerdeff1(a):returna@register(alias='fn3')# <- (1)deff2(a):returna

上述api的简单实现将不起作用。上面标记为(1)的行将失败,因为未传递第一个参数fn。但我们希望输出是一样的。

更好的解决方案

importbiwrap@biwrap.biwrapdefregister(fn,alias=None):iffn.__name__notinregister.storage:register.storage[fn.__name__]=fnelifregister.storage[fn.__name__]isnotfn:raiseKeyError('{} is already in storage'.format(fn.__name__))ifaliasisnotNoneandaliasnotinregister.storage:register.storage[alias]=fnelifaliasisnotNone:raiseKeyError('{} is already in storage'.format(alias))returnfnregister.storage={}@registerdeff1(a):returnaprint(register.storage)#> {'f1': <function f1 at 0x10f45a048>}@register(alias='fn3')deff2(a):returnaprint(register.storage)#> {'f1': <function f1 at 0x10f45a048>, 'f2': <function f2 at 0x10f45a488>, 'fn3': <function f2 at 0x10f45a488>}

功能概述

可能存在一些角情况,自定义编码可以为每个用例创建一个样板(见图SO thread)。这个包采用了最好的方法,实现了简单但通用的解决方案来解决所有问题。.

设置

以一个简单的包装器为例。它将根据参数化打印hibye,默认值为hi

importbiwrap@biwrap.biwrapdefhiwrap(fn,hi=True):defnew(*args,**kwargs):ifhi:print('hi')else:print('bye')returnfn(*args,**kwargs)returnnew

病例

函数包装

定义的包装可以以两种方式使用

@hiwrapdeffn(n):print(n)fn(1)#> hi#> 1@hiwrap(hi=False)deffn(n):print(n)fn(1)#> bye#> 1

绑定方法包装器

biwrap也适用于绑定方法。如SO thread所示,这可能是一个问题,因为第一个位置参数是self,而不是函数。

classW:def__init__(self,n):self.n=n@biwrap.biwrapdefwrap(self,fn,text='hi'):defwrapped(*args,**kwargs):for_inrange(self.n):print(text)returnfn(*args,**kwargs)returnwrappedwr=W(3)@wr.wrapdeffn(n):print(n)fn(1)#> hi#> hi#> hi#> 1@wr.wrap(text='bye')deffn(n):print(n)wr.n=2fn(2)#> bye#> bye#> 2

类方法/属性包装

实现也处理这些情况

classO:def__init__(self,n):self.n=n@classmethod@hiwrapdeffn(cls,n):print(n)@property@hiwrap(hi=False)defnum(self):returnself.no=O(2)o.fn(1)#> hi#> 1print(o.num)#> bye#> 2

包装器作为函数

像call这样的函数也可以

deffn(n):print(n)fn=hiwrap(fn,hi=False)fn(1)#> bye#> 1

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

推荐PyPI第三方库


热门话题
java Springboot数据JPA findByDate()   java是否可以有多个顶级树节点?   javahibernatehql。子查询中的多个   使用Twilio验证java Keyclope电话号码   java重写对象的toString()表示返回意外的符号   java Android最多每15分钟调用一个方法,否则使用保存的数据   在java swing中突出显示jeditorpane中的一些单词   java将时间戳转换为UTC时区   由于main中存在ArrayIndexOutOfBoundsException,导致java编译错误   java如何通过requestscope获取对象内部对象的值?   java访问安卓代码内的网站并检索生成的图像   java这种日期格式的模式是什么?   java解析包含超链接的xml字符串