Python 函数重载实现

Python 不支持函数重载,在同一个模块中声明同名方法不会报错,只会不停的覆盖,无论参数个数是否不同,最终只会保留最后一个函数

输出

foo(a: str)
<function foo at 0x107e74c10>
Traceback (most recent call last):
File ".../scratches/scratch_1.py", line 12, in <module>
foo(3, 5)
TypeError: foo() takes 1 positional argument but 2 were given

只有最后一个 foo 函数是存在的,在 globals() 只有一个 foo

那么 Python 要怎么实现函数重载呢?Python 3.4 在 functools 下添加了 singledispatch, Python 3.8 又继续加入了 singledispatchmethod。Python 的文档 https://docs.python.org/3/glossary.html#term-generic-functionPEP443 说它们的功用是支持单一分派的泛型函数。但本人觉得更像是函数重载。

为什么说是单分派(single dispatch)呢? 因为它只能根据第一个参数的类型选择要实际执行的函数。看下面的实例

在 IDE 中我们可以在 breakpoint() 处打个断点来调试,或者运行直接进入  pdb 控制台查看运行状态

输出为

0x103dbd790
0x103dbd8b0
0x103dbd940
1 - 1
str - 2
main []

pdb

(Pdb) foo.registry
mappingproxy({<class 'object'>: <function foo at 0x103da2c10>, <class 'int'>: <function _foo at 0x103dbd8b0>, <class 'str'>: <function _foo at 0x103dbd940>})
(Pdb) foo
<function foo at 0x103dbd790>
(Pdb) _foo
<function _foo at 0x103dbd940>

从这里我们就能发现它的实现方式,singledispatch 装饰的函数 foo 用 @foo.register(cls) 来注册声明的方法,并存储在 foo.registry 属性中,调用 foo(x) 时便根据第一个参数的类型进行分派,默认会调用在 foo.registry 中的 <class 'object'> 对应的实现上,即代理到被 @singledispatch 装饰的函数的实现

singledispatchmethod 的用法

参考 Python 官方文档的实例

执行后输出为 

-1
False

那能不能根据构造实例时的类型来判断调用哪个 neg() 方法呢?大概想要实现的是

Negator(1).neg()  -> 得到 -1
negator(True).neg()  -> 得到 False

尝试写成下面那样

执行后出错

method = self.dispatcher.dispatch(args[0].__class__)
IndexError: tuple index out of range

所以函数还是必须要有至少一个参数才能代理到正确的方法实现上去,虽然注册方法是没有问题的

result = {function} <function Negator.neg at 0x107a82700>
registry = {mappingproxy: 3} {<class 'object'>: <function Negator.neg at 0x107a82430>, <class 'int'>: <function Negator._ at 0x107a82820>, <class 'bool'>: <function Negator._ at 0x107a828b0>}

本文链接 https://yanbin.blog/python-overload/, 来自 隔叶黄莺 Yanbin Blog

[版权声明] Creative Commons License 本文采用 署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0) 进行许可。

Subscribe
Notify of
guest

0 Comments
Inline Feedbacks
View all comments