【问题标题】:Python 3.5 - method overloading with @overloadPython 3.5 - 使用@overload 重载方法
【发布时间】:2016-09-28 13:23:15
【问题描述】:

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

常见编码模式:

class foo:
  def func(param):
    if instance(param, int):
      pass
    elif instance(param, str):
      pass
    elif instance(param, list):
      pass
    else:
      raise ValueError()

使用@overload:

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

  @overload
  def func(param: str):
    pass

  @overload
  def func(param: list):
    pass

这里是documentation


我的问题是:

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

【问题讨论】:

  • 通用编码模式 -- 不,不是,抱歉。大多数 Python 代码不需要使用isinstance()
  • 请注意,该包并非特定于 Python 3.5。 Python 3.5 仅标准化类型提示,但从 Python 3.0 开始提供注释。您链接到的软件包支持 3.3 及更高版本;您的示例根本不使用 typing 模块。
  • source code 应该让您回答第二个问题(它读取函数注释,正如预期的那样)。看着dispatcher(),我首先会选择“较慢”。
  • 哦,我不知道 3.5 之前支持的类型提示。
  • 类型提示只是注释。在 typing 模块被添加到 3.5 之前,没有关于如何使用注释进行类型提示的标准。该示例使用内置类型(intstrlist),因此不需要typing,而且我认为该库不支持泛型(我怀疑它可以区分@987654334 @ 和 Sequence[int])。

标签: python python-3.5 overloading


【解决方案1】:

您必须使用真实代码自行测量。

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

看看这些行:

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)

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)

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

【讨论】:

    【解决方案2】:

    从 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)
    

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

    >>> 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
    

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-09-29
      • 1970-01-01
      • 2018-01-31
      • 2012-04-29
      • 1970-01-01
      • 2010-09-30
      • 1970-01-01
      相关资源
      最近更新 更多