Python不支持函数重载,那就写一个

  前段时间学习C++,发现C++有个函数重载的情况。

  (以下介绍来自百度百科)重载函数是函数的一种特殊情况,为方便使用,C++允许在同一范围中声明几个功能类似的同名函数,但是这些同名函数的形式参数(指参数的个数、类型或者顺序)必须不同,也就是说用同一个函数完成不同的功能。这就是重载函数。重载函数常用来实现功能类似而所处理的数据类型不同的问题。不能只有函数返回值类型不同。

  我查了一下关于Python的函数重载,发现Python并不支持函数重载。

  但是,我发现可以通过其他的一些方法,来实现这个函数重载。

  通过在网上搜索,找到一些使用Python实现函数重载的方法,这其中就有几种“假的”函数重载,他们根本就没有领会到函数重载的优雅之处。

  最后看到一个博客上写的用Python实现的函数重载,我觉得非常的好,在这里就与大家分享一下。

      博客来源:https://arpitbhayani.me/blogs/function-overloading

  实现过程主要分为三个部分,1、包装函数(Wrapped the function);2、构建虚拟命名空间(Building the virtual Namespace);3、使用使用装饰器作为钩子(Using decorators as a hook)。

/01/ 包装函数

  包装函数的目的在于,可以包装任何函数,并通过一个被覆盖的__call__方法使其可调用,同时它还公开了一个名为key的方法,该方法会返回一个元组,这使得这个函数在整个代码库中是唯一的。

class Function(object):
    def __init__(self, fn):
        self.fn = fn
    def __call__(self, *args, **kwargs):
        fn = Namespace.get_instance().get(self.fn, *args)
        if not fn:
            raise Exception("No matching function found.")
        return fn(*args, *kwargs)

    def key(self, args=None):
        if args is None:
            args = getfullargspec(self.fn).args

        return tuple(
            [
                self.fn.__module__,
                self.fn.__class__,
                self.fn.__name__,
                len(args or []),
            ]
        )

/02/ 构建虚拟命名空间

  构建的虚拟命名空间将存储我们在定义阶段收集的所有函数。由于这里只有一个命名空间/注册表,我们创建了一个单例类来将函数保存在一个字典中,这个字典的键将不仅仅是一个函数名,而是我们从key函数获得的元组,它包含了在整个代码库中唯一标识函数的元素。通过这样做,我们就可以在注册表中保存函数了,即使它们有相同的名称(但有不同的参数),从而促进函数重载。

class Namespace(object):
    __instance = None
    def __init__(self):
        if self.__instance is None:
            self.function_map = dict()
            Namespace.__instance = self
        else:
            raise Exception("Cannot instantiate a virtual Namespace again")

    @staticmethod
    def get_instance():
        if Namespace.__instance is None:
            Namespace()
        return Namespace.__instance

    def register(self, fn):
        func = Function(fn)
        self.function_map[func.key()] = fn
        return func

    def get(self, fn, *args):
        func = Function(fn)
        return self.function_map.get(func.key(args=args))

/03/ 使用装饰器作为钩子

  因此,创建了名为overload的装饰器,它会在虚拟命名空间中注册这个新包装器函数并返回一个可调用对象。

def overload(fn):
    return Namespace.get_instance().register(fn)

/04/ 测试

@overload
def area(a, b):
    s = a * b
    print("长方形的面积是:", s)
    return s

@overload
def area(r):
    s = 3.14 * r ** 2
    print("圆的面积是:", round(s, 2))
    return s

@overload
def area(a, b, c) -> float:
    v = a * b * c
    print("立方体的体积是:", v)
    return v

if __name__ == "__main__":
    area(2)
    area(3, 4)
    area(1, 2, 3)

这才是有灵魂的函数重载嘛!


▼​

函数重载也算是为自己多提供了一个思路。

猜你喜欢

转载自www.cnblogs.com/aiMiku/p/12403727.html