可选参数后的重载

问题描述

我有一个带有方法 Animal 的类 foo,它根据跟随可选参数 inplace 的布尔参数 bar 具有不同的返回类型。我想重载该函数,以便在 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,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 错误

解决方法

试试:

@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 的顺序,否则第二次重载不应该是正确的。

,

这似乎有效:

from __future__ import annotations

from typing import Optional,overload,Literal 


class Animal:

    # using defaults
    @overload
    def foo(self,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,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))

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