如何根据参数值更改函数的提示 return 类型
How can I change the hinted return type of a function depending on the value of a parameter
我有一个函数,它通常 return 搜索一个对象并执行一些其他操作。如果找不到匹配项,它会引发异常。通常,我不在乎它是否找到匹配项,但频率不够高以至于我会考虑完全删除异常。因此,我做出的妥协是创建一个默认为 True
的参数 raise_on_failure
。如果它是 False
,那么 None
是 returned 而不是引用。
def searchAndOperate(f, raise_on_failure: bool = True) -> Optional[Foo]:
# Search
result = ...
if result is None:
if raise_on_failure: raise ValueError("No results")
else: return None
# Operate
...
# Then return the result
return result
但是,这导致我的类型提示出现一些问题。我想这样做,如果 raise_on_failure
是 True
,则函数保证 return 一个 Foo
,这样如果 [=] 只有 Optional[Foo]
13=] 是 False
.
我该怎么做?类似于以下代码片段的内容是最理想的,但我也愿意接受其他想法。
def searchAndOperate(
f,
raise_on_failure: bool = True
) -> Foo if raise_on_failure else Optional[Foo]:
...
从概念上讲,我认为根据参数变化的类型提示没有意义。
类型提示 Optional[Foo]
已经封装了 searchAndOperate
能够 return 的所有内容:任何调用它的人都知道它会 return Foo
或 None
。尝试根据 raise_on_failure
的值“拆分”return 类型会将函数的行为与其实现耦合起来。您应该做的是 重构函数本身 以便它的行为是 non-ambiguous。对您当前类型提示的不满源于 searchAndOperate
试图一次做太多事情。
例如,searchAndOperate
可以拆分为 single-responsibility 函数 search
和 operate
。或者您可以完全放弃 raise_on_failure
参数,而将函数调用留给调用者 try/except 。如果它成为你经常做的事情,你可以将它包装成一个单独的函数,比如:
def searchAndOperate(f) -> Foo:
"""Searches and returns Foo. Raises a ValueError if no result is found."""
result = ...
if result is None:
raise ValueError("No result")
return result
def trySearchAndOperate(f) -> Optional[Foo]:
"""Searches and returns Foo. Returns None if no result is found."""
try:
result = searchAndOperate(f)
except ValueError:
return None
这样,当没有找到结果时,调用者已经知道会发生什么。您可能认为这有点重复,但它是一种常见模式:'abc'.index(s)
和 'abc'.find(s)
之间的唯一区别是如果 s
在 'abc'
,第二个 return 在这种情况下是默认值 -1
。
我不确定这是否可行。
return 类型提示应该告诉您,无需查看参数的值,函数 returns.
您实际上是在这个函数中实现两种不同的行为:
- Return一个
Foo
或崩溃
- Return一个
Foo
或None
如果你想在类型提示中对此进行编码,你必须考虑这两种情况。这意味着函数 是 Optional[Foo]
.
如果你不想这样,我建议把这个功能拆分成两个不同的功能;一个加注,一个加点:
def search_and_operate(f) -> Optional[Foo]:
result = ... # some code that either results in a Foo object or None
return result
def search_and_operate_or_raise(f) -> Foo:
result = search_and_operate(f)
if result is None:
raise ValueError("No result")
return result
我有一个函数,它通常 return 搜索一个对象并执行一些其他操作。如果找不到匹配项,它会引发异常。通常,我不在乎它是否找到匹配项,但频率不够高以至于我会考虑完全删除异常。因此,我做出的妥协是创建一个默认为 True
的参数 raise_on_failure
。如果它是 False
,那么 None
是 returned 而不是引用。
def searchAndOperate(f, raise_on_failure: bool = True) -> Optional[Foo]:
# Search
result = ...
if result is None:
if raise_on_failure: raise ValueError("No results")
else: return None
# Operate
...
# Then return the result
return result
但是,这导致我的类型提示出现一些问题。我想这样做,如果 raise_on_failure
是 True
,则函数保证 return 一个 Foo
,这样如果 [=] 只有 Optional[Foo]
13=] 是 False
.
我该怎么做?类似于以下代码片段的内容是最理想的,但我也愿意接受其他想法。
def searchAndOperate(
f,
raise_on_failure: bool = True
) -> Foo if raise_on_failure else Optional[Foo]:
...
从概念上讲,我认为根据参数变化的类型提示没有意义。
类型提示 Optional[Foo]
已经封装了 searchAndOperate
能够 return 的所有内容:任何调用它的人都知道它会 return Foo
或 None
。尝试根据 raise_on_failure
的值“拆分”return 类型会将函数的行为与其实现耦合起来。您应该做的是 重构函数本身 以便它的行为是 non-ambiguous。对您当前类型提示的不满源于 searchAndOperate
试图一次做太多事情。
例如,searchAndOperate
可以拆分为 single-responsibility 函数 search
和 operate
。或者您可以完全放弃 raise_on_failure
参数,而将函数调用留给调用者 try/except 。如果它成为你经常做的事情,你可以将它包装成一个单独的函数,比如:
def searchAndOperate(f) -> Foo:
"""Searches and returns Foo. Raises a ValueError if no result is found."""
result = ...
if result is None:
raise ValueError("No result")
return result
def trySearchAndOperate(f) -> Optional[Foo]:
"""Searches and returns Foo. Returns None if no result is found."""
try:
result = searchAndOperate(f)
except ValueError:
return None
这样,当没有找到结果时,调用者已经知道会发生什么。您可能认为这有点重复,但它是一种常见模式:'abc'.index(s)
和 'abc'.find(s)
之间的唯一区别是如果 s
在 'abc'
,第二个 return 在这种情况下是默认值 -1
。
我不确定这是否可行。
return 类型提示应该告诉您,无需查看参数的值,函数 returns.
您实际上是在这个函数中实现两种不同的行为:
- Return一个
Foo
或崩溃 - Return一个
Foo
或None
如果你想在类型提示中对此进行编码,你必须考虑这两种情况。这意味着函数 是 Optional[Foo]
.
如果你不想这样,我建议把这个功能拆分成两个不同的功能;一个加注,一个加点:
def search_and_operate(f) -> Optional[Foo]:
result = ... # some code that either results in a Foo object or None
return result
def search_and_operate_or_raise(f) -> Foo:
result = search_and_operate(f)
if result is None:
raise ValueError("No result")
return result