社区所有版块导航
Python
python开源   Django   Python   DjangoApp   pycharm  
DATA
docker   Elasticsearch  
aigc
aigc   chatgpt  
WEB开发
linux   MongoDB   Redis   DATABASE   NGINX   其他Web框架   web工具   zookeeper   tornado   NoSql   Bootstrap   js   peewee   Git   bottle   IE   MQ   Jquery  
机器学习
机器学习算法  
Python88.com
反馈   公告   社区推广  
产品
短视频  
印度
印度  
Py学习  »  Python

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

Python编程 • 3 年前 • 407 次点击  
来自公众号:程序员zhenguo

你好,我是zhenguo

我们知道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.01.0)
foo('2.0s''1.0s')

打印结果如下所示:

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

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

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

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


--- EOF ---


推荐↓↓↓
Python社区是高质量的Python/Django开发社区
本文地址:http://www.python88.com/topic/123654
 
407 次点击