非泛型类方法上的字典类型变量

问题描述 投票:0回答:1

关于以下代码:

from typing import Generic
from typing import TypeVar
from typing import reveal_type


T = TypeVar('T')


class Field(Generic[T]):
    """A field definition with a default value."""

    def __init__(self, default_value: T):
        self.default_value = default_value


class FieldDataCollection:
    """A collection of field values."""

    def __init__(self, value_per_field: dict[Field[T], T]) -> None:
        self._value_per_field = value_per_field

    def get_field_value(self, field: Field[T]) -> T:
        """Return the field value if in the collection or the field default value."""
        return self._value_per_field.get(field, field.default_value)


if __name__ == '__main__':
    foo = Field(1)
    value = FieldDataCollection({foo: 2}).get_field_value(foo)
    reveal_type(value)

在严格模式下运行 1.11.0(但不是以前的版本)时,我从 mypy 中收到以下错误:

error: Incompatible return value type (got "T@__init__", expected "T@get_field_value")  [return-value]
error: Argument 1 to "get" of "dict" has incompatible type "Field[T@get_field_value]"; expected "Field[T@__init__]"  [arg-type]
error: Argument 2 to "get" of "dict" has incompatible type "T@get_field_value"; expected "T@__init__"  [arg-type]
note: Revealed type is "builtins.int"

根据我对这些错误的理解,mypy 抱怨

__init__
方法中推断的类型与
get_field_value
方法中的类型有所不同。

我尝试为

get_field_value
使用不同类型的变量:

T = TypeVar("T")
Tfield = TypeVar("Tfield")

...

class FieldDataCollection:
    ...

    def get_field_value(self, field: Field[Tfield]) -> Tfield:
        ...

但是 mypy 似乎发现了差异并以同样的方式抱怨:

error: Incompatible return value type (got "T", expected "Tfield")  [return-value]
error: Argument 1 to "get" of "dict" has incompatible type "Field[Tfield]"; expected "Field[T]"  [arg-type]
error: Argument 2 to "get" of "dict" has incompatible type "Tfield"; expected "T"  [arg-type]
note: Revealed type is "builtins.int"

我尝试使用

Mapping
MutableMapping
而不是
dict
,效果很好,但是我无法使用
dict
之类的方法,如
copy

你认为这是 mypy 方面的回归吗? 否则,您知道如何正确注释

FieldDataCollection
类吗?

python python-typing mypy
1个回答
0
投票

这似乎实际上是一个范围问题,

FieldDataCollection
中的类型T未定义,因此解释不同,在这种情况下不是您正在寻找的解释。将
Generic[T]
添加到
FieldDataCollection
可以解决 mypy 版本 1.11.0 中的此问题,因为它确保
__init__
中使用的类型必须与
get_field_value
中使用的类型相同:

from typing import Generic
from typing import TypeVar
from typing import reveal_type


T = TypeVar('T')


class Field(Generic[T]):
    """A field definition with a default value."""

    def __init__(self, default_value: T):
        self.default_value = default_value


class FieldDataCollection(Generic[T]):
    """A collection of field values."""

    def __init__(self, value_per_field: dict[Field[T], T]) -> None:
        self._value_per_field = value_per_field

    def get_field_value(self, field: Field[T]) -> T:
        """Return the field value if in the collection or the field default value."""
        return self._value_per_field.get(field, field.default_value)


if __name__ == '__main__':
    foo = Field(1)
    value = FieldDataCollection({foo: 2}).get_field_value(foo)
    reveal_type(value)

希望这有帮助!

© www.soinside.com 2019 - 2024. All rights reserved.