我发现自己编写了很多函数,我希望能够对参数 x、y、...
、 和 的集合进行操作,例如[(x1, y1, ...), (x2, y2, ...), ...]
。
是否有一个清晰简单的装饰器、模式或技术来编写这样的函数?
这是一个任意示例:
def awesome(func):
# ???
@awesome
def mult(a, b):
return a * b
mult(3, 4) # should return 12
mult((3, 4)) # should return 12 or possibly (12,)
mult(((3, 4), (2, 3), [3, 3])) # should return (12, 6, 9)
mult([(3, 4), [4, 5]]) # should return (12, 20)
最佳答案
Python 3.4 引入 single-dispatch generic functions与 @singledispatch
装饰器,提供了一种简单的方法来在使用不同参数类型调用同一函数时实现不同的行为。例如,要允许您的 mult()
函数接受可迭代对象:
from functools import singledispatch
from collections.abc import Iterable
@singledispatch
def mult(a, b):
return a * b
@mult.register(Iterable)
def _(it):
return [mult(a, b) for a, b in it]
函数的“基本”版本用 @singledispatch
修饰,将其转换为通用函数。接下来,定义函数 _()
来对可迭代中的每个元素调用 mult()
,并使用 @mult.register( )
。
尽管上面的示例使用 collections.abc.Iterable
为了最大程度地通用,还可以为多个具体类型注册一个函数:
@mult.register(list)
@mult.register(tuple)
def _(it):
return [mult(a, b) for a, b in it]
使用上面的技术,可以编写一个装饰器@takes_iterable
,它将任意函数转换为通用函数,并向其注册另一个函数以适本地处理可迭代对象:
def takes_iterable(func):
generic = singledispatch(func)
@generic.register(Iterable)
def _(it):
return [func(*args) for args in it]
return generic
@takes_iterable
def mult(a, b):
return a * b
使用示例:
>>> mult(17,23)
391
>>> mult([(11, 29), (13, 23), (17, 19)])
[319, 299, 323]
警告:正如 Blckknght 在评论中指出的那样,如果调用用 @takes_iterable
修饰的函数并希望其以“单一”方式运行,您将得到意外的结果模式,但向其传递一个恰好可迭代的参数,例如字符串。
这实际上是问题中所要求的行为固有的模糊性的结果,而不是此处概述的实现,但在考虑是否使用此技术时值得牢记。
关于python - python装饰器可以使函数能够智能地操作单个对象和集合对象吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6128227/