栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Python

Python会不会支持函数重载?龟叔仅用30行代码搞定

Python 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Python会不会支持函数重载?龟叔仅用30行代码搞定

你好,我是zhenguo

在公众号建立四周年之际,我将一直沿用的公众号名字 Python与算法社区 修改为 程序员zhenguo,

希望你能继续关注带有蜜蜂头像 程序员zhenguo 的公众号,我确信你一定能从我这里学到一些真正有用的Python和算法知识,获取到我精选的相关资料。

最近几天时间写出这么一篇文章,参考Python创建者龟叔在2005年写的一篇博文,是关于Python函数重载的话题,从龟叔的30行代码中就能看出他的非凡智慧,我有幸在上面做出一些修改。

我们知道Python语法本身并不支持函数重载,龟叔2005年写的一篇博文中说到:函数重载太高级了以至于他不会用到。但是龟叔不愧是仁慈大叔,他依然给出了Python实现函数重载的方法,代码实现在我看来简洁高级又明确。

因为不支持函数重载,所以下面两个f的定义,第二个会覆盖第一个,因此调用第一个会报错:第一个

def f(a: int):
    print(f'a={a}')

第二个

def f(a: int, b: float):
    print(f'a={a}, b')

调用第一个:

f(1)

打印:

TypeError: f() missing 1 required positional argument: 'b'

龟叔使用装饰器对待重载的函数进行增强,使用registry作为函数字典,函数名为键,值为封装的MultiMethod对象

# 这是 mm.py 中代码
# 这是函数重载装饰器multimethod
def multimethod(*types):
    def register(f):
        f_name = f.__name__
        mm = registry.get(f_name)
        if mm is None:
            mm = registry[f_name] = MultiMethod(f_name)
        mm.register(types, f)
        return mm
    return register

MultiMethod内部封装的type_dict属性是同一个函数名下的不同版本字典,注意只支持位置参数,使用参数组合类型作为key,其值为对应函数f

# 这是 mm.py 中代码
# 模块级变量
registry = {} # 函数注册字典

class MultiMethod(object):
    def __init__(self, f_name):
        self.f_name = f_name
        self.type_dict = {}
        
    def __call__(self, *args):
        types = tuple(type(arg) for arg in args) # 生成器表达式
        print(f"函数名={self.f_name}, 参数类型={types}")
        function = self.type_dict.get(types)
        if function is None:
            raise TypeError(f"{types}不支持")
        return function(*args)
    
    def register(self, types, function):
        if types not in self.type_dict:
            self.type_dict[types] = function

这样后multimethod装饰器就具备函数重载功能,以下foo分别重载2个int,2个float,2个str

@multimethod(int, int)
def foo(a, b):
   # 对整型a和b处理
   print(f"a={a}, b={b}")

@multimethod(float, float)
def foo(a, b):
    # 对浮点型a和b处理
   print(f"a={a}, b={b}")

@multimethod(str, str)
def foo(a, b):
    # 对字符串a和b处理
   print(f"a={a}, b={b}")

最后foo就可以实现函数重载了,调用它们:

foo(2,1)
foo(2.0, 1.0)
foo('2.0s', '1.0s')

打印结果如下所示:

函数名=foo, 参数类型=()
a=2, b=1

函数名=foo, 参数类型=()
a=2.0, b=1.0

函数名=foo, 参数类型=()
a=2.0s, b=1.0s

参考龟叔的这篇博文:https://www.artima.com/weblogs/viewpost.jsp?thread=101605

若有任何问题,都可以留言交流。另外,我正在视频号里分享一些Python干货,欢迎关注:

长按关注我的视频号:程序员zhenguo

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/357461.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号