可选参数后的重载

Posted

技术标签:

【中文标题】可选参数后的重载【英文标题】:overload following optional argument 【发布时间】:2021-05-31 18:22:36 【问题描述】:

我有一个类Animal 和一个方法foo,它根据一个可选参数bar 后面的布尔参数inplace 具有不同的返回类型。我想重载该函数,以便在知道inplace 的值的情况下知道返回类型

这是我的代码:

# main.py

from __future__ import annotations

from typing import Optional, overload, Literal 


class Animal:
    @overload
    def foo(self, bar=..., inplace: Literal[False]=...) -> Animal:
        ...

    @overload
    def foo(self, bar=..., inplace: Literal[True]=...) -> None:
        ...

    def foo(
        self, bar=None, inplace: bool = False
    ) -> Optional[Animal]:
        ...


reveal_type(Animal().foo(bar='a'))
reveal_type(Animal().foo(inplace=True))
reveal_type(Animal().foo(inplace=False))
$ mypy main.py
main.py:8: error: Overloaded function signatures 1 and 2 overlap with incompatible return types
main.py:21: note: Revealed type is 'main.Animal'
main.py:22: note: Revealed type is 'None'
main.py:23: note: Revealed type is 'main.Animal'
Found 1 error in 1 file (checked 1 source file)

https://mypy-play.net/?mypy=latest&python=3.9&gist=49da369f6343543769eed2060fa61639

如何避免第 8 行出现 Overloaded function signatures 1 and 2 overlap with incompatible return types 错误?

【问题讨论】:

【参考方案1】:

这似乎有效:

from __future__ import annotations

from typing import Optional, overload, Literal 


class Animal:

    # using defaults
    @overload
    def foo(self, bar=..., inplace: Literal[False]=...) -> Animal: ...

    # using inplace = True
    
    # with bar
    @overload
    def foo(self, bar, inplace: Literal[True]) -> None: ...

    # without bar
    @overload
    def foo(self, *, inplace: Literal[True]) -> None: ...

    # with bool
    @overload
    def foo(self, bar=..., inplace: bool=...) -> Optional[Animal]: ...

    def foo(
        self, bar=None, inplace = False
    ):
        ...


reveal_type(Animal().foo(bar='a'))
reveal_type(Animal().foo(bar='a', inplace=True))
reveal_type(Animal().foo(bar='a', inplace=False))
reveal_type(Animal().foo(inplace=True))
reveal_type(Animal().foo(inplace=False))
reveal_type(Animal().foo())

inplace: bool
reveal_type(Animal().foo(bar='a', inplace=inplace))
reveal_type(Animal().foo(inplace=inplace))

很多重载,但也许这在这里是不可避免的

【讨论】:

【参考方案2】:

试试:

@overload
def foo(self, inplace: Literal[False]=..., bar=...) -> Animal:
    ...

@overload
def foo(self, inplace: Literal[True], bar=...,) -> None:
    ...

def foo(self, inplace=False, bar=None):
    ...

我更改了 args 的顺序,否则第二次重载不正确。

【讨论】:

我无法更改def foo 中的参数顺序,恐怕这将是一个重大更改

以上是关于可选参数后的重载的主要内容,如果未能解决你的问题,请参考以下文章

与可选参数冲突的重载方法

C#4.0中的方法重载与可选参数[重复]

可选函数参数:使用默认参数(NULL)还是重载函数?

打字稿重载、可选参数和类型推断

在 C# 4.0 中是不是应该使用重载或可选参数声明方法?

C# 4 中的重载分辨率和可选参数