Mypy 的类变量是类的实例

问题描述 投票:0回答:3

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

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
3个回答
1
投票

您可以注释变量而不为其赋值。这在这里很有用,因为您不能使用类型的名称

Thing
在其自己的类主体中创建实例,因为全局名称
Thing
直到创建类对象之后才定义。所以你只需要一个注释,其值稍后定义。

缺少全局名称

Thing

 也是您迄今为止对属性进行注释的尝试不起作用的原因。解决方案是使用带引号的字符串进行前向引用。在定义 
"Thing"
 之前,您可以使用 
Thing
 来注释类实例所在的位置。

(Python 3.11 将于 2022 年秋季发布,将包括

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


0
投票
正如已删除的答案中所述(如果可以的话投票取消删除):

请注意,如果您使用

from __future__ import annotations
你可以这样做:

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

    

0
投票
在这种情况下我声明这样的类。

from typing import ClassVar from typing import Self class Thing: EMPTY_THING: ClassVar[Self] @classmethod def __defaults__(cls) -> None: cls.EMPTY_THING = cls() Thing.__defaults__() if __name__ == '__main__': assert Thing.EMPTY_THING is not None
    
© www.soinside.com 2019 - 2024. All rights reserved.