Python中的重载

方法重载是面向对象中一个非常重要的概念,在类中包含了成员方法和构造方法。如果类中存在多个同名,且参数(个数和类型)不同的成员方法或构造方法,那么这些成员方法或构造方法就被重载了

java案例

class MyOverload {
    public MyOverload() {
        System.out.println("MyOverload");
    }
    public MyOverload(int x) {
        System.out.println("MyOverload_int:" + x);
    }
    public MyOverload(long x) {
        System.out.println("MyOverload_long:" + x);
    }
    public MyOverload(String s, int x, float y, boolean flag) {
        System.out.println("MyOverload_String_int_float_boolean:" + s + x  + y + flag);
    }
}

先说结论:python语法上不支持重载,但可通过魔法方法或装饰器实现重载的效果

Python版本>=3.8 : functools 新增了一个 singledispatchmethod 方法,这个方法可以让 Python 的类方法支持 重载,使用方法和 singledispatch 类似,唯一需要注意的是,重载的类型是由类函数中第一个非 selfcls 的参数类型决定的,singledispatchmethod 还支持嵌套的装饰器,不过需要注意的是,dispatcher.registersingledispatchmethod 需要在绝大多数装饰器的最上层

官方实例:

class Negator:
    @singledispatchmethod
    def neg(self, arg):
        raise NotImplementedError("Cannot negate a")

    @neg.register
    def _(self, arg: int):
        return -arg

    @neg.register
    def _(self, arg: bool):
        return not arg

Python版本<3.8 : 借鉴singledispatchmethod实现

3.8源码

class singledispatchmethod:
    """Single-dispatch generic method descriptor.

    Supports wrapping existing descriptors and handles non-descriptor
    callables as instance methods.
    """

    def __init__(self, func):
        if not callable(func) and not hasattr(func, "__get__"):
            raise TypeError(f"{func!r} is not callable or a descriptor")

        self.dispatcher = singledispatch(func)
        self.func = func

    def register(self, cls, method=None):
        """generic_method.register(cls, func) -> func

        Registers a new implementation for the given *cls* on a *generic_method*.
        """
        return self.dispatcher.register(cls, func=method)

    def __get__(self, obj, cls=None):
        def _method(*args, **kwargs):
            method = self.dispatcher.dispatch(args[0].__class__)
            return method.__get__(obj, cls)(*args, **kwargs)

        _method.__isabstractmethod__ = self.__isabstractmethod__
        _method.register = self.register
        update_wrapper(_method, self.func)
        return _method

    @property
    def __isabstractmethod__(self):
        return getattr(self.func, '__isabstractmethod__', False)


################################################################################
### cached_property() - computed once per instance, cached as attribute
################################################################################

_NOT_FOUND = object()

具体实现:

需要重载处添加如下代码:

from functools import singledispatch, update_wrapper

def methdispatch(func):
    dispatcher = singledispatch(func)
    def wrapper(*args, **kw):
        return dispatcher.dispatch(args[1].__class__)(*args, **kw)
    wrapper.register = dispatcher.register
    update_wrapper(wrapper, func)
    return wrapper

测试代码:

class Negator:
@methdispatch
def neg(self, arg):
    raise NotImplementedError("Cannot negate a")

@neg.register
def _(self, arg: int):
    return -arg

@neg.register
def _(self, arg: bool):
    return not arg

if __name__ == '__main__':
neg = Negator()
neg.neg(1)
neg.neg(False)

# 输出如下:
# -1
# True

其他
在 pypi 上也有对应的 singledispatchmethod · PyPI 库,可以通过 pip 安装后直接使用,用法和 3.8 之后版本用法一致。

参考内容:

python 中实现类方法重载 - 知乎 (zhihu.com)

卧槽,好强大的魔法,竟能让Python支持方法重载 - 腾讯云开发者社区-腾讯云 (tencent.com)

posted @ 2022-07-07 16:46  KMP  阅读(3446)  评论(0编辑  收藏  举报