我想在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 中那样进行函数重载(即没有分支)?
有使用装饰器或某些库的明确方法吗?
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的设计方式。另外,如果您有很多复杂的重载,并且都需要不同的实现逻辑,我认为这“可能”只是糟糕的设计。如果分支像您的示例一样清晰/简单,那么我认为将它们放在一个函数体中没有问题。
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