簡體   English   中英

Mypy 帶有作為類實例的類變量

[英]Mypy with class variable that is an instance of the class

我正在嘗試創建一個帶有類變量的類,該類變量表示該類的一個空實例。 我目前擁有的是

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 EMPTY = None並將其分配到類之外,Mypy 會不高興,因為它認為EMPTY的類型是None

如果我嘗試使用Optional[Thing]作為類型來注釋EMPTY ,那么我會在定義之前重新使用Thing

有沒有解決方案,或者我只需要告訴 Mypy 忽略EMPTY字段?

我正在使用python 3.9。

您可以在不為其賦值的情況下對變量進行注釋。 這在這里很有用,因為您不能使用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

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

請注意,如果您使用

from __future__ import annotations

你可以這樣做:

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM