mypy AnyStr 在简单示例的赋值中给出了不兼容的类型
mypy AnyStr gives Incompatible types in assignment on trivial example
给出以下 class:
from typing import AnyStr
class A(object):
def __init__(self, param):
# type: (AnyStr) -> None
self.a = param # type: AnyStr
我得到以下输出:
$ mypy . -v
LOG: Mypy version 0.521
LOG: Build finished in 1.199 seconds with 10 modules, 2076 types, and 2 errors
test.py:8: error: Incompatible types in assignment (expression has type "str", variable has type "AnyStr")
test.py:8: error: Incompatible types in assignment (expression has type "bytes", variable has type "AnyStr"
这个赋值操作怎么会给出不兼容的类型?
我不是 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"
这是有道理的,因为来自 the documentation 的 AnyStr
的想法是 或者 str
或者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
是全局的(而且上面的例子表明它是而不是),那么在原始[的范围之外赋值一个变量=16=] 变量(例如全局变量,或 class 的属性)没有意义,这可能是它失败的原因。我怀疑错误消息可能对此更加清楚。
解决方案
根据您实际想要完成的事情,这里有一些解决方案。如果你真的不知道 str
和 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]
,因为只有一个参数。或者,如果您实际上 do 关心参数是 str
还是 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。
给出以下 class:
from typing import AnyStr
class A(object):
def __init__(self, param):
# type: (AnyStr) -> None
self.a = param # type: AnyStr
我得到以下输出:
$ mypy . -v
LOG: Mypy version 0.521
LOG: Build finished in 1.199 seconds with 10 modules, 2076 types, and 2 errors
test.py:8: error: Incompatible types in assignment (expression has type "str", variable has type "AnyStr")
test.py:8: error: Incompatible types in assignment (expression has type "bytes", variable has type "AnyStr"
这个赋值操作怎么会给出不兼容的类型?
我不是 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"
这是有道理的,因为来自 the documentation 的 AnyStr
的想法是 或者 str
或者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
是全局的(而且上面的例子表明它是而不是),那么在原始[的范围之外赋值一个变量=16=] 变量(例如全局变量,或 class 的属性)没有意义,这可能是它失败的原因。我怀疑错误消息可能对此更加清楚。
解决方案
根据您实际想要完成的事情,这里有一些解决方案。如果你真的不知道 str
和 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]
,因为只有一个参数。或者,如果您实际上 do 关心参数是 str
还是 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。