给出Accessing dict keys like an attribute?中第一个答案的示例:
class AttrDict(dict):
def __init__(self, *args, **kwargs):
super(AttrDict, self).__init__(*args, **kwargs)
self.__dict__ = self
和一个返回以下内容的函数:
def dict_to_attrdict(somedict):
return AttrDict(**somedict)
分配为:
data = dict_to_attrdict(mydict)
在给定以下约束的情况下,将通过mypy检查的类和函数添加类型提示的正确方法是什么:
str
Any
表示,因为它们不一样,我不希望分别输入,例如一些str
,List[dict[str, List]]
,{{1} },Dict[str, str]
答案 0 :(得分:1)
您可以通过以下操作使类和函数定义自己进行类型检查:
from typing import Dict, Any
class AttrDict(Dict[str, Any]):
def __init__(self, *args: Any, **kwargs: Any) -> None:
super(AttrDict, self).__init__(*args, **kwargs)
self.__dict__ = self
def dict_to_attrdict(some: Dict[str, Any]) -> AttrDict:
return AttrDict(**some)
从Dict[X, Y]
继承与在运行时仅从dict
继承没什么不同,但是它为mypy提供了所需的额外元数据。
但是,您实际上将无法以类型安全的方式使用AttrDict
的实例:mypy始终会将my_attrdict.foo
之类的内容标记为错误。
这是因为在所有情况下都无法静态确定AttrDict
中将出现什么字段-mypy不知道AttrDict
中到底存在什么。而且由于mypy无法判断出my_attrdict.foo
之类的事情是否实际上是安全的,因此它倾向于保守主义,只是决定考虑这种不安全行为。
您可以通过两种不同的方法来解决此问题。首先,如果您真正想让AttrDict
尽可能保持动态,则可以告诉mypy仅假定该类型是任意动态类型,如下所示:
from typing import Dict, Any, TYPE_CHECKING
if TYPE_CHECKING:
AttrDict = Any
else:
class AttrDict(dict):
def __init__(self, *args, **kwargs) -> None:
super(AttrDict, self).__init__(*args, **kwargs)
self.__dict__ = self
def dict_to_attrdict(some: Dict[str, Any]) -> AttrDict:
return AttrDict(**some)
TYPE_CHECKING
是一个在运行时始终为False的值,但被mypy视为始终为True的值。最终结果是,mypy只考虑if / else的'if'分支,而忽略了'else'分支中的所有内容:我们现在告诉mypy AttrDict
是 type别名Any
的em>:完全等同于Any
。但是,在运行时,我们总是会陷入“ else”分支并像以前一样定义类。
此方法的主要缺点是,使用静态类型确实没有任何价值。我们现在可以强制要求键必须是字符串,因此我们可以为dict_to_attrdict
添加一点安全性。
第二种选择是利用mypy的优势并重写代码以实际使用类。因此,我们将摆脱AttrDict
并使用设置其字段的类。
这使mypy可以了解存在的字段,字段的类型等。需要做一些前期工作,但好处是mypy可以为您提供代码正确性的有力保证。>
如果您发现实际上定义了一堆带有字段的类很乏味,请尝试使用新的“数据类”模块(如果使用的是Python 3.7)或第三方的“ attrs”模块。我相信mypy最近增加了对两者的支持。
如果您想使用数据类,则可能要等到本周二发布mypy 0.620时-我不记得该功能是否将其添加到mypy 0.600或mypy 0.610中。