3

给定以下课程:

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"

这个分配操作怎么会给出不兼容的类型?

4

1 回答 1

1

我不是 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文档中 的想法 ,它旨在成为stror 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变量(例如全局,或者一个类的属性)是没有意义的,这很可能为什么失败。我怀疑错误消息可能对此更加清楚。

解决方案

根据您实际想要完成的任务,这里有一些解决方案。如果您真的在strand之间不可知论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。

于 2017-07-27T19:31:55.480 回答