python-3.x 如何根据是否给出了参数(如next()函数)来类型注解不同的返回类型?

t98cgbkg  于 2023-11-20  发布在  Python
关注(0)|答案(1)|浏览(145)

next()函数有一个特殊的属性,即next(iterable)返回元素或引发异常,但next(iterable, None)返回元素或None。
如何类型注解它?考虑以下情况,我使用pyright检查:

from typing import TypeVar, Union

R = TypeVar('R')

class SuperNone:
  pass
    
class MyDict:
   data = { "a": 1 }

   def get(
      self, key: str, default: R = SuperNone
   ) -> Union[R, Elem] if R == SuperNone else Elem:
      try:
         return self.data[key]
      except KeyError:
         if isinstance(default, SuperNone):
             raise
         else:
             return default

a: int = MyDict().get("a")  # Expression of type "SuperNone | int" cannot be assigned to declared type "int"
b: Union[int, str] = MyDict().get("a", "")

# vs next() function is fine:
c: int = next((x for x in [1]))
d: Union[int, str] = next((x for x in [1]), "")

字符串
这不起作用,如何“动态”使返回类型化值?

ukqbszuj

ukqbszuj1#

您可以使用overload实现此类型。这不会影响运行时,重载“艾德”签名仅用于类型检查器。以下是解决此问题的方法:

from typing import TypeVar, Union, Final, overload, Generic

_R = TypeVar('_R')
_T = TypeVar('_T')
  
_SENTINEL: Final = object()

class MyDict(Generic[_R]):
    data: dict[str, _R]
    
    def __init__(self, x: _R) ->None:
        ...    
    
    @overload
    def get(self, key: str) -> _R: ...
    @overload
    def get(self, key: str, default: _T) -> _T | _R: ...
    def get(
        self, key: str, default: object = _SENTINEL
    ) -> _T | object:
        try:
            return self.data[key]
        except KeyError:
            if default is _SENTINEL:
                raise
            else:
                return default

reveal_type(MyDict(1).get("a"))
reveal_type(MyDict(1).get("a", None))
reveal_type(MyDict(1).get("a", ""))

字符串
下面是一个playground link(注意,不需要构建一个单独的类来创建唯一的sentinel)
如果你不知道重载,你有一个很好的例子-next。你可以去看看它的类型是如何在typeshed中定义的:

@overload
def next(__i: SupportsNext[_T]) -> _T: ...
@overload
def next(__i: SupportsNext[_T], __default: _VT) -> _T | _VT: ...

相关问题