如何在Python中进行函数重载?

问题描述 投票:0回答:2

我想在Python中实现函数重载。我知道默认情况下Python不支持重载。这就是我问这个问题的原因。

我有以下代码:

def parse():
    results = doSomething()  
    return results 
x = namedtuple('x',"a b c")

def parse(query: str, data: list[x]):
    results = doSomethingElse(query, data)
    return results

我能想到的唯一解决方案是检查参数:

def parse(query: str, data: list[x]):
    if query is None and data is None:
       results = doSomething()  
       return results 
    else:
       results = doSomethingElse(query, data)   
       return results

Python 中是否可以像 Java 中那样进行函数重载(即没有分支)?

有使用装饰器或某些库的明确方法吗?

python python-3.x overloading decorator python-decorators
2个回答
4
投票

typing.overload
装饰器,用于使用两个或多个不同的调用签名正确注释可调用对象。但它仍然需要一次实际的实施。用法如下:

from typing import overload


@overload
def parse(query: None = None, data: None = None) -> None:
    ...


@overload
def parse(query: str, data: list[object]) -> None:
    ...


def parse(query: str | None = None, data: list[object] | None = None) -> None:
    if query is None and data is None:
        print("something")
    else:
        print(f"something else with {query=} and {data=}")


parse()            # something
parse("foo", [1])  # something else with query='foo' and data=[1]

请注意,省略号

...
是字面意思,即该函数重载的“主体”中应包含所有内容。

这就是 Python 中的实现方式。正如评论中已经提到的,没有用于字面编写重载函数实现的语法。如果您编写两个实现,最后一个将简单地覆盖第一个。

即使你可以用语法上令人愉悦的装饰器构建类似的东西,我可能会建议你不要这样做,因为它可能会让其他人感到困惑,因为这不是Python的设计方式。另外,如果您有很多复杂的重载,并且都需要不同的实现逻辑,我认为这“可能”只是糟糕的设计。如果分支像您的示例一样清晰/简单,那么我认为将它们放在一个函数体中没有问题。


0
投票
singledispatch

functools
来做到这一点。
functools.singledispath
了解更多信息。 您的示例假设您从函数返回 list[x],即

results

:

from functools import singledispatch

@singledispatch
def parse(query, data: list[x]) -> list[x]:
    return []

@parse.register
def _(query: str, data: list[x]) -> list[x]:
    results = doSomethingElse(query, data)
    return results

@parse.register
def _(query: list[str], data: list[x]) -> list[x]:
    results = doSomethingElseWithListOfStr(query, data)
    return results

您可以 
register

只要重载函数的返回类型相同即可。

parse.register
的格式为
functionname.register
。因此,如果您定义了一个需要重载的
foo
函数,则将其注册为
foo.register
    

© www.soinside.com 2019 - 2024. All rights reserved.