如何修复 pylint E1134:非映射值 X 用于映射上下文(非映射)
How to fix pylint E1134: Non-mapping value X is used in a mapping context (not-a-mapping)
pylint (2.12.2) 正在回归
E1134: Non-mapping value self.f_four is used in a mapping context (not-a-mapping)
对于下面的代码
from dataclasses import dataclass
@dataclass
class One:
f_one: str
f_two: str
@dataclass
class Two:
f_three: str
f_four: One
def __post_init__(self):
"""Initialise nested dataclass fields from a dictionary"""
self.f_four = One(**self.f_four)
data = {'f_three': 'three', 'f_four': {'f_one': 'one', 'f_two': 'two'}}
print(Two(**data)) # prints: Two(f_three='three', f_four=One(f_one='one', f_two='two'))
相对于dataclasses.field the documentation says:
metadata: This can be a mapping or None. None is treated as an empty dict. This value is wrapped in MappingProxyType() to make it read-only, and exposed on the Field object. It is not used at all by Data Classes, and is provided as a third-party extension mechanism. Multiple third-parties can each have their own key, to use as a namespace in the metadata.
我尝试用 f_four: One = field(metadata="Mapping")
更新 Two
class。但这会导致 mypy 错误(但解决了 pylint 错误)因此,此 metadata
必须不正确或至少不足以正确修复此问题。
更改行的 Mypy 错误是
error: No overload variant of "field" matches argument type "str"
note: Possible overload variants:
note: def [_T] field(*, default: _T, init: bool = ..., repr: bool = ..., hash: Optional[bool] = ..., compare: bool = ..., metadata: Optional[Mapping[Any, Any]] = ...) -> _T
note: def [_T] field(*, default_factory: Callable[[], _T], init: bool = ..., repr: bool = ..., hash: Optional[bool] = ..., compare: bool = ..., metadata: Optional[Mapping[Any, Any]] = ...) -> _T
note: def field(*, init: bool = ..., repr: bool = ..., hash: Optional[bool] = ..., compare: bool = ..., metadata: Optional[Mapping[Any, Any]] = ...) -> Any
那么如何正确解决这个pylint错误呢?
在你的代码中我看到两个错误,一个来自 pylint,一个来自 mypy:
pylint 错误
self.f_four = One(**self.f_four)
# Non-mapping value self.f_four is used in a mapping context
pylint 错误发生是因为数据的 specially generated __init__
class:
def __init__(f_three: str, f_four: One)
f_four
是一个 class One
实例,它不接受 **
.
pylint的一种解决方案是手动定义__init__
的签名,
并将 __post_init__
的正文移动到 __init__
:
from typing import Union
@dataclass
class Two:
f_three: str
f_four: One
# __init__ f_four accepts both One and dict
def __init__(self, f_three: str, f_four: Union[One, dict]):
self.f_three = f_three
if isinstance(f_four, dict):
self.f_four = One(**f_four)
else:
self.f_four = f_four
或者,如果您想保留 __post_init__
,则允许 Two.f_four
为:Union[One, dict]
:
from typing import Union
@dataclass
class Two:
f_three: str
f_four: Union[One, dict]
def __post_init__(self):
"Initialise nested dataclass fields from a dictionary"
if isinstance(self.f_four, dict):
self.f_four = One(**self.f_four)
mypy错误
print(Two(**data))
# Argument 1 to "Two" has incompatible type "**Dict[str, Collection[str]]";
# expected "str"
# Argument 1 to "Two" has incompatible type "**Dict[str, Collection[str]]";
# expected "One"
存在 mypy 错误,因为 **data
与中的类型提示不匹配
Two.__init__
。要修复 mypy 错误,我们需要 TypedDict
:
from typing import TypedDict
class TwoDict(TypedDict):
f_three: str
f_four: Union[One, dict]
并且我们必须对 mypy 类型提示说 data
具有类型 TwoDict
:
data: TwoDict = {'f_three': 'three', 'f_four': {'f_one': 'one', 'f_two': 'two'}}
pylint (2.12.2) 正在回归
E1134: Non-mapping value self.f_four is used in a mapping context (not-a-mapping)
对于下面的代码
from dataclasses import dataclass
@dataclass
class One:
f_one: str
f_two: str
@dataclass
class Two:
f_three: str
f_four: One
def __post_init__(self):
"""Initialise nested dataclass fields from a dictionary"""
self.f_four = One(**self.f_four)
data = {'f_three': 'three', 'f_four': {'f_one': 'one', 'f_two': 'two'}}
print(Two(**data)) # prints: Two(f_three='three', f_four=One(f_one='one', f_two='two'))
相对于dataclasses.field the documentation says:
metadata: This can be a mapping or None. None is treated as an empty dict. This value is wrapped in MappingProxyType() to make it read-only, and exposed on the Field object. It is not used at all by Data Classes, and is provided as a third-party extension mechanism. Multiple third-parties can each have their own key, to use as a namespace in the metadata.
我尝试用 f_four: One = field(metadata="Mapping")
更新 Two
class。但这会导致 mypy 错误(但解决了 pylint 错误)因此,此 metadata
必须不正确或至少不足以正确修复此问题。
更改行的 Mypy 错误是
error: No overload variant of "field" matches argument type "str"
note: Possible overload variants:
note: def [_T] field(*, default: _T, init: bool = ..., repr: bool = ..., hash: Optional[bool] = ..., compare: bool = ..., metadata: Optional[Mapping[Any, Any]] = ...) -> _T
note: def [_T] field(*, default_factory: Callable[[], _T], init: bool = ..., repr: bool = ..., hash: Optional[bool] = ..., compare: bool = ..., metadata: Optional[Mapping[Any, Any]] = ...) -> _T
note: def field(*, init: bool = ..., repr: bool = ..., hash: Optional[bool] = ..., compare: bool = ..., metadata: Optional[Mapping[Any, Any]] = ...) -> Any
那么如何正确解决这个pylint错误呢?
在你的代码中我看到两个错误,一个来自 pylint,一个来自 mypy:
pylint 错误
self.f_four = One(**self.f_four)
# Non-mapping value self.f_four is used in a mapping context
pylint 错误发生是因为数据的 specially generated __init__
class:
def __init__(f_three: str, f_four: One)
f_four
是一个 class One
实例,它不接受 **
.
pylint的一种解决方案是手动定义__init__
的签名,
并将 __post_init__
的正文移动到 __init__
:
from typing import Union
@dataclass
class Two:
f_three: str
f_four: One
# __init__ f_four accepts both One and dict
def __init__(self, f_three: str, f_four: Union[One, dict]):
self.f_three = f_three
if isinstance(f_four, dict):
self.f_four = One(**f_four)
else:
self.f_four = f_four
或者,如果您想保留 __post_init__
,则允许 Two.f_four
为:Union[One, dict]
:
from typing import Union
@dataclass
class Two:
f_three: str
f_four: Union[One, dict]
def __post_init__(self):
"Initialise nested dataclass fields from a dictionary"
if isinstance(self.f_four, dict):
self.f_four = One(**self.f_four)
mypy错误
print(Two(**data))
# Argument 1 to "Two" has incompatible type "**Dict[str, Collection[str]]";
# expected "str"
# Argument 1 to "Two" has incompatible type "**Dict[str, Collection[str]]";
# expected "One"
存在 mypy 错误,因为 **data
与中的类型提示不匹配
Two.__init__
。要修复 mypy 错误,我们需要 TypedDict
:
from typing import TypedDict
class TwoDict(TypedDict):
f_three: str
f_four: Union[One, dict]
并且我们必须对 mypy 类型提示说 data
具有类型 TwoDict
:
data: TwoDict = {'f_three': 'three', 'f_four': {'f_one': 'one', 'f_two': 'two'}}