我不是 mypy 方面的专家,但是通过一些侦探工作,我想我已经弄清楚了。
问题
如果将其传递给函数,这似乎工作得很好AnyStr
,但是当变量键入为AnyStr
. 例如,这似乎工作正常:
from typing import AnyStr
def f(a):
# type: (AnyStr) -> AnyStr
return a
if __name__ == "__main__":
print(f('cat'))
print(f(b'dog'))
但这失败了:
from typing import AnyStr
c = 3 # type: AnyStr
出现错误:
mypy_anystr.py:3: error: Invalid type "typing.AnyStr"
这是有道理的,因为AnyStr
从文档中 的想法是 ,它旨在成为str
or bytes
,但它必须在给定函数调用的范围内保持一致。他们给出的AnyStr
用法示例是:
def concat(a, b):
#type: (AnyStr, AnyStr) -> AnyStr
return a + b
concat('one', 'two') # OK
concat(b'three', b'four') # OK
concat('five', b'six') # Error
当然,除非AnyStr
是全局的(上面的例子表明它不是),那么在原始变量的范围之外分配一个AnyStr
变量(例如全局,或者一个类的属性)是没有意义的,这很可能为什么失败。我怀疑错误消息可能对此更加清楚。
解决方案
根据您实际想要完成的任务,这里有一些解决方案。如果您真的在str
and之间不可知论bytes
,那么您可以使用Union[Text, bytes]
:
从输入 import Union, Text, AnyStr
class A:
def __init__(self, a):
#type: (AnyStr) -> None
self.param = a # type: Union[Text, bytes]
请注意,在这种情况下,我AnyStr
在输入上使用了,但在这种情况下,它等效于Union[Text, bytes]
,因为只有一个参数。或者,如果您确实关心参数是 astr
还是bytes
,则可以AnyStr
将其主动转换为您想要的版本:
from typing import Union, Text, AnyStr
from six import binary_type
class A:
def __init__(self, a):
#type: (AnyStr) -> None
if isinstance(a, binary_type):
b = a.decode() # type: Text
else:
b = a
self.param = b # type: Text
请注意,如果a
在奇怪的语言环境或其他地方编码,这可能会变得很时髦,因此请注意,如果您尝试主动解码bytes
对象,这是一个简化的示例和 YMMV。