python装饰器可以使函数能够智能地对单个对象和对象进行操作吗?

问题描述

| 我发现自己写了很多函数,希望能够对参数ѭ0operate以及诸如的集合进行操作。
[(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,5]])          # should return (12,20)
    

解决方法

Python 3.4在
@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]
函数的\'base \'版本以ѭ3修饰,将其转换为通用函数。接下来,定义一个函数“ 7”以迭代方式在每个元素上调用“ 4”,并用“ 9”注册到通用函数。 尽管上面的示例出于最大的通用性而使用了“ 10”,但也可以为多种具体类型注册一个函数:
@mult.register(list)
@mult.register(tuple)
def _(it):
    return [mult(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]
CAVEAT:正如Blckknght在评论中所指出的那样,如果调用一个用
@takes_iterable
装饰的函数,使其打算以“单”模式运行,但是将一个恰好可迭代的参数传递给它,则您会得到意想不到的结果。串。 这确实是问题所要求的行为固有的歧义而不是此处概述的实现的结果,但是在考虑是否使用此技术时,应牢记这一点。