【问题标题】:Best way to "overload" function in python? [duplicate]在python中“重载”函数的最佳方法? [复制]
【发布时间】:2015-06-07 11:50:13
【问题描述】:

我正在尝试在 python 中做这样的事情:

def foo(x, y):
    # do something at position (x, y)

def foo(pos):
    foo(pos.x, pos.y)

所以我想根据我提供的参数数量调用不同版本的 foo。这当然行不通,因为我重新定义了foo

实现这一目标的最优雅的方式是什么?我宁愿不使用命名参数。

【问题讨论】:

  • 在Python中有默认参数...
  • 您需要针对该语言工作才能做到这一点。我宁愿只提供一个重载。
  • 在 pypi 上查看 overload
  • @behzad.nouri:男孩,每次调用其中一个函数时,那个装饰器肯定会运行a lot of code。这几乎不是处理此问题的有效方法。
  • @MartijnPieters 可能,但它看起来很酷 :)

标签: python overloading


【解决方案1】:

通常你要么定义两个不同的函数,要么做类似的事情:

def foo(x, y = None):
    if y is None:
        x, y = x.x, x.y
    # do something at position (x, y)

如果您习惯于具有重载的语言,则定义两个不同函数的选项似乎很笨拙,但如果您习惯于没有重载的 Python 或 C 等语言,那么这就是您所做的。上述Python代码的主要问题是第一个参数记录起来有点别扭,这两种情况下的意思不一样。

另一种选择是定义采用 pos 的 foo 的版本,但也为用户提供类型:

Pos = collections.namedtuple('Pos', 'x y')

那么任何会写foo(x,y) 的人都可以改写foo(Pos(x,y))。自然会有一点性能开销,因为必须创建一个对象。

【讨论】:

    【解决方案2】:

    你可以使用默认参数,但是如果你想在python中使用重载,最好的方法是:

    from pytyp.spec.dispatch import overload
    
    @overload
    def foo(x,y):
    
    @foo.overload
    def foo(x, y,z):
    

    Pytyp 是一个 python 包(你可以从https://pypi.python.org/pypi/pytyp 下载它)。它包括模块 pytyp.spec.dispatch,其中包含装饰器,如重载。如果放在方法上,所有重载的方法都会调用这个方法..

    【讨论】:

    • @overload 装饰器的定义在哪里?这不是标准 Python 库的一部分。
    • 感谢通知我已添加导入语句。
    • 那么这里的pytyp 是什么?有人需要安装什么才能为他们工作?
    • 我也添加了这方面的信息。
    【解决方案3】:

    您可以做很多事情,例如命名默认参数。

    但是,您想要的是“多次调度”,并且有许多装饰器实现可以帮助您完成此类事情。这是one implementation,看起来像:

    >>> from multipledispatch import dispatch
    
    >>> @dispatch(int, int)
    ... def add(x, y):
    ...     return x + y
    
    >>> @dispatch(Position)
    ... def add(pos):
    ...     return "%s + %s" % (pos.x, pos.y)
    
    >>> add(1, 2)
    3
    
    >>> pos = Position(3, 4)
    >>> add(pos)
    7
    

    虽然@functools.singledispatch 即将来到Python 3.4,但我认为这不适用于您的示例,因为在一种情况下您有多个参数。

    【讨论】:

    • 我猜这意味着你失去了单参数版本的鸭式打字,对吗?它必须采用Position,而不是具有.x.y 的任何其他类型?我想您仍然可以使用 ABC 进行调度。
    • 如果你想在那个实现中做鸭子类型,你可以做“@dispatch(object, object)”。我只是假设如果你真的想要多次调度你不想躲避类型;-)
    【解决方案4】:

    你想要实现的设计看起来很糟糕,也许可以考虑使用不同的函数名称:

    def do_something_by_coordinates(x, y):
        pass
    
    def do_something_by_position(pos):
        do_something_by_coordinates(pos.x, pos.y)
    

    如果您确实需要,也可以使用kwargs
    Understanding kwargs in Python

    【讨论】:

    • 如果不是一个好的设计,那为什么Python有min而不是min_of_iterablemin_of_arguments左右呢?
    • 因为min 使用这样的设计实际上是有意义的。也许我不应该使用“不是一个好的设计”而是“闻起来像糟糕的设计”这样的词,因为无论这是否真的是一个糟糕的设计,都取决于我们不知道的更大的背景。
    【解决方案5】:

    设置默认值的一种方式:

    def foo(x, y=None):    
        # now for example, you can call foo(1) and foo(1,2)     
    

    foo 中,您可以检查y == None 是否为这两种情况的不同逻辑。

    请注意,如果您将功能分开,您可以有更好的设计,不要尝试拥有同时接受坐标和位置的相同功能。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-12-28
      • 1970-01-01
      • 1970-01-01
      • 2015-01-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-09-17
      相关资源
      最近更新 更多