Python 3.5 - 使用 @overload 重载方法

Pae*_*els 8 python overloading python-3.5

Python 3.5+有一个重载包。使用这个包,可以重新定义方法,但是具有不同的类型提示,并且它的装饰器会找出应该调用哪个重载方法。

常见的编码模式:

class foo:
  def func(param):
    if instance(param, int):
      pass
    elif instance(param, str):
      pass
    elif instance(param, list):
      pass
    else:
      raise ValueError()
Run Code Online (Sandbox Code Playgroud)

使用@overload:

class foo:
  @overload
  def func(param: int):
    pass

  @overload
  def func(param: str):
    pass

  @overload
  def func(param: list):
    pass
Run Code Online (Sandbox Code Playgroud)

这是文档


我的问题是:

  • 与旧式参数类型切换相比,性能影响有多大?
  • 这个包如何访问类型提示?

Gra*_*ist 5

从 python 3.4 开始,有一个核心 API 功能functools.singledispatch,它允许您注册重载函数。

从文档中

>>> from functools import singledispatch
>>> @singledispatch
... def fun(arg, verbose=False):
...     if verbose:
...         print("Let me just say,", end=" ")
...     print(arg)

>>> @fun.register
... def _(arg: int, verbose=False):
...     if verbose:
...         print("Strength in numbers, eh?", end=" ")
...     print(arg)

>>> @fun.register
... def _(arg: list, verbose=False):
...     if verbose:
...         print("Enumerate this:")
...     for i, elem in enumerate(arg):
...         print(i, elem)
Run Code Online (Sandbox Code Playgroud)

运行上述函数时(再次来自文档):

>>> fun("Hello, world.")
Hello, world.
>>> fun("test.", verbose=True)
Let me just say, test.
>>> fun(42, verbose=True)
Strength in numbers, eh? 42
>>> fun(['spam', 'spam', 'eggs', 'spam'], verbose=True)
Enumerate this:
0 spam
1 spam
2 eggs
3 spam
Run Code Online (Sandbox Code Playgroud)

注意:仅输入第一个参数!

此外,(自 python 3.8 起)还有一个等效的类方法调用functools.singledispatchmethod 的装饰器


小智 4

你必须用真实的代码自己测量它。

我快速浏览了这个库的代码,结论很简单。它使用了大量的反射(检查包)和类型比较。检查包本身主要由调试工具使用 - 它们总是会减慢你的代码速度。

只要看看这些行:

complexity = complexity_mapping[id]
if complexity & 8 and isinstance(arg, tuple):
     element_type = tuple(type(el) for el in arg)
elif complexity & 4 and hasattr(arg, 'keys'):
     element_type = (type(element), type(arg[element]))
else:
     element_type = type(element)
Run Code Online (Sandbox Code Playgroud)

type_hints = typing.get_type_hints(func) if typing else func.__annotations__
types = tuple(normalize_type(type_hints.get(param, AnyType)) for param in parameters)
Run Code Online (Sandbox Code Playgroud)

请注意,此包如果已存在超过 7 个月且只有 70 颗星。Python 不是 Java...你真的会用这个包伤害 python 本身 :D 你最好实现一些核心 api 方法,根据类型参数将调用委托给其他方法/对象 - 就像 Python 应该做的那样。