使 Class 常量谁的类型是它所在的 Class

Making A Class Constant Who's Type Is The Class In Which It Resides

我有一个 Python class 具有特殊值,“EMPTY”和“UNIVERSE”:

class RealSet:
    """Continuous open, half-open, and closed regions and discreet values of the Reals"""

    # implementation placeholder
    def __init__(self, intervals, *, canonicalize):
        pass

# Outside the class

RealSet.EMPTY = RealSet(tuple(), canonicalize=False)  # type: ignore
RealSet.UNIVERSE = RealSet(((None, None),), canonicalize=False)  # type: ignore

然而,linting、代码完成等不喜欢这样,因为它们不被视为 class 的静态属性。即使设置它们也被报告为 mypy 错误,因此 # type: ignore.

以下不起作用,因为我无法在 class 范围内构建 RealSet,因为它尚不存在:

class RealSet:
    """Continuous open, half-open, and closed regions and discreet values of the Reals"""
    ...
    ...

    EMPTY = RealSet(tuple(), canonicalize=False)  # error
    UNIVERSE = RealSet(((None, None),), canonicalize=False)  # error

这不起作用,因为它定义了实例属性,而不是 class 属性:

class RealSet:
    """Continuous open, half-open, and closed regions and discreet values of the Reals"""
    ...
    ...

    EMPTY: "RealSet"
    UNIVERSE: "RealSet"

# Outside the class

RealSet.EMPTY = RealSet(tuple(), canonicalize=False)
RealSet.UNIVERSE = RealSet(((None, None),), canonicalize=False)

这似乎是 Python classes 设计中的一个极端情况。如何创建 class 属性,其中属性的类型是它所在的 class?奖励:让它们保持不变。

您可以使用typing.ClassVar注释class个变量:

class RealSet:
    def __init__(self, intervals, *, canonicalize):
        pass

    EMPTY: ClassVar['RealSet']
    UNIVERSE: ClassVar['RealSet']


RealSet.EMPTY = RealSet(tuple(), canonicalize=False)
RealSet.UNIVERSE = RealSet(((None, None),), canonicalize=False)

从Python3.9开始classmethod可以修饰property等其他描述。这样就可以创建一个“类属性”:

class RealSet:
    def __init__(self, intervals, *, canonicalize):
        pass

    @classmethod
    @property
    def EMPTY(cls):
        return cls(tuple(), canonicalize=False)

    @classmethod
    @property
    def UNIVERSE(cls):
        return cls(((None, None),), canonicalize=False)