您好, 欢迎来到 !    登录 | 注册 | | 设为首页 | 收藏本站

用于Python重载的装饰器

用于Python重载的装饰器

PyPI上有一个重载包,尽管使用的语法略有不同,但它比我在下面描述的功能更强大。它被声明仅适用于Python 3,但看起来仅需进行少量修改(如果有,我还没有尝试过)就可以使其与Python 2一起使用。

在可以重载函数的语言中,无论是在定义函数时还是在调用函数时,函数名称都会(在字面上或有效地)增加有关其类型签名的信息。当编译器或解释器查找函数定义时,它将使用声明的名称和参数类型来解析要访问的函数。因此,在Python中实现重载的逻辑方法是实现一个包装器,该包装器使用声明的名称和参数类型来解析函数

这是一个简单的实现:

from collections import defaultdict

def deter@R_419_2177@_types(args, kwargs):
    return tuple([type(a) for a in args]), \
           tuple([(k, type(v)) for k,v in kwargs.iteritems()])

function_table = defaultdict(dict)
def overload(arg_types=(), kwarg_types=()):
    def wrap(func):
        named_func = function_table[func.__name__]
        named_func[arg_types, kwarg_types] = func
        def call_function_by_signature(*args, **kwargs):
            return named_func[deter@R_419_2177@_types(args, kwargs)](*args, **kwargs)
        return call_function_by_signature
    return wrap

overload应该使用两个可选参数来调用一个表示所有位置参数类型的元组一个表示所有关键字参数名称类型映射的元组元组。这是一个用法示例:

>>> @overload((str, int))
... def f(a, b):
...     return a * b

>>> @overload((int, int))
... def f(a, b):
...     return a + b

>>> print f('a', 2)
aa
>>> print f(4, 2)
6

>>> @overload((str,), (('foo', int), ('bar', float)))
... def g(a, foo, bar):
...     return foo*a + str(bar)

>>> @overload((str,), (('foo', float), ('bar', float)))
... def g(a, foo, bar):
...     return a + str(foo*bar)

>>> print g('a', foo=7, bar=4.4)
aaaaaaa4.4
>>> print g('b', foo=7., bar=4.4)
b30.8

缺点包括

@overload((str, int))

def h(): return 0

并且在调用函数时会出现错误

它不能很好地处理与所传递的参数类型相对应的不存在任何重载版本的情况(这将有助于引发更具描述性的错误

它区分命名参数和位置参数,所以类似

g('a', 7, bar=4.4)

不起作用。

我认为,所有这些都可以通过足够的摆弄来补救。特别是,通过将调度表存储为从装饰器返回的函数属性,可以轻松解决名称冲突的问题。但是,正如我所说的,这只是一个简单的示例,以演示如何做的基础。

python 2022/1/1 18:33:09 有477人围观

撰写回答


你尚未登录,登录后可以

和开发者交流问题的细节

关注并接收问题和回答的更新提醒

参与内容的编辑和改进,让解决方法与时俱进

请先登录

推荐问题


联系我
置顶