python装饰器能否使函数能够智能地对单个对象和集合对象进行操作?
我发现自己编写了很多函数,希望能够对参数python装饰器能否使函数能够智能地对单个对象和集合对象进行操作?,python,generics,collections,decorator,Python,Generics,Collections,Decorator,我发现自己编写了很多函数,希望能够对参数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))
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)
Python3.4引入了decorator,提供了一种简单的方法来实现使用不同参数类型调用同一函数时的不同行为。例如,要允许mult()
函数接受iterables:
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
修饰,将其转换为通用函数。接下来,定义一个函数。
,对iterable中的每个元素调用mult()
,并使用@mult.register()
注册到泛型函数
尽管上面的示例出于最大的通用性考虑而使用,但也可以为多个具体类型注册函数:
@mult.register(list)
@mult.register(tuple)
def _(it):
return [mult(a, b) for a, b in it]
使用上述技术,可以编写一个decorator@takes\u iterable
,将任意函数转换为泛型函数,并向其注册另一个函数以适当处理iterables:
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\u iterable
修饰的函数以“single”模式运行,但向它传递一个恰巧是iterable的参数(如字符串),则会得到意想不到的结果
这实际上是问题中要求的行为固有的模糊性而不是此处概述的实现的结果,但在考虑是否使用此技术时,值得记住。整个想法并不好,因为您最终不知道此函数的输入和输出,这使得发现bug变得更加困难。只需键入(mul(*x)代表xs中的x)
我们为什么不直接使用管道类型和运算符重载呢?看起来更加直观和复杂的是字符串是可写的。因此,如果原始函数采用单个字符串作为参数,代码无法判断func(“abc”)
应该是一个调用还是三个调用func(“a”);func(“b”);func(“c”)
@Blckknght这是一个很好的观点(在上面Jochen Ritzel的基础上进行扩展)。我已经更新了答案,并提出了警告。