【问题标题】:Mypy with class variable that is an instance of the classMypy 带有作为类实例的类变量
【发布时间】:2022-06-23 16:59:00
【问题描述】:

我正在尝试创建一个带有类变量的类,该类变量表示该类的一个空实例。我目前拥有的是

from collections import namedtuple
# from typing import Optional

_Thing = namedtuple("_Thing", ["foo", "bar"])

class Thing(_Thing):
    __slots__ = ()

    def baz(self):
        print("foo", self.foo)

    # NameError: name 'Thing' is not defined
    # EMPTY = Thing(None, None)

Thing.EMPTY = Thing(None, None)

if __name__ == '__main__':
    thing = Thing.EMPTY

    thing.baz()

    print("Done")

我也在尝试在代码上运行 Mypy。当我运行python simple.py 时,它按预期运行:

$ python simple.py && mypy simple.py 
foo None
Done
simple.py:15: error: "Type[Thing]" has no attribute "EMPTY"
simple.py:18: error: "Type[Thing]" has no attribute "EMPTY"
Found 2 errors in 1 file (checked 1 source file)

但 Mypy 很不高兴,因为 Thing 的声明没有定义 EMPTY

如果我在类中取消注释EMPTY 的定义,我会得到一个NameError,因为我试图在定义Thing 时引用它。

如果我尝试在类中将EMPTY 声明为EMPTY = None 并将其分配到类外,Mypy 会不高兴,因为它认为EMPTY 的类型是None

如果我尝试将 EMPTY 注释为 Optional[Thing] 作为类型,那么我会在定义之前重新使用 Thing

是否有解决方案,或者我只需要告诉 Mypy 忽略 EMPTY 字段?

我正在使用 python 3.9。

【问题讨论】:

    标签: python mypy


    【解决方案1】:

    您可以在不为其赋值的情况下对变量进行注释。这在这里很有用,因为您不能使用 Thing 类型的名称在其自己的类主体中创建实例,因为全局名称 Thing 直到 类对象被创建。因此,您只需要一个注释,其值稍后定义。

    缺少全局名称Thing 也是您迄今为止尝试注释该属性的尝试无效的原因。解决方案是使用带引号的字符串进行前向引用。在定义Thing 之前,您可以使用"Thing" 来注释您的类实例的位置。

    (将于 2022 年秋季推出的 Python 3.11 将包含 PEP 673,它将提供一种更好的方式来从类的主体或方法中引用“当前类”:typing.Self。它将是非常适合解决我们的前向参考问题,但还没有出来。)

    在类主体中注释属性通常会告诉类型检查器该属性将是一个实例变量(这是类型检查器将做出的默认假设)。如果您打算将属性作为类变量,则需要在注解中使用typing.ClassVar 来表明这一点。

    所以,把这些放在一起,你可能想要这样的东西:

    import typing
    
    class Thing(_Thing):
        EMPTY: typing.ClassVar["Thing"]
        #...
    
    Thing.EMPTY = Thing(None, None)
    

    如果您曾经将此代码升级到 Python 3.11,可以将注释中的 "Thing" 替换为 typing.Self

    【讨论】:

      【解决方案2】:

      如已删除答案中所述(如果可以,请投票取消删除):

      注意,如果你使用

      from __future__ import annotations
      

      你可以这样做:

      ...
      class Thing(_Thing):
          EMPTY: typing.ClassVar[Thing]
          ...
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2011-01-06
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-10-10
        • 2012-11-16
        • 1970-01-01
        相关资源
        最近更新 更多