将 mypy 与实例属性的延迟初始化一起使用

Bek*_*eka 5 python mypy python-typing

更新:尝试检查/填充另一个函数中的值


我正在尝试在我的项目中使用 mypy,但是我使用的许多实例属性仅在 之后初始化__init__,而不是在其中初始化。但是,我确实希望保持在 处声明所有实例属性的良好做法__init__,因此我需要一些复杂的解决方案来完成这项工作。

我希望它如何表现的一个例子(目前 mypy 正在抱怨):

from typing import Optional

class Foo:
    def __init__(self, x: int):
        self.x = x
        self.y: int = None  # will initialize later, but I know it will be an int

    def fill_values(self):
        self.y = x**2

    def do(self) -> int:
        return self.x + self.y
Run Code Online (Sandbox Code Playgroud)

目前 mypy 抱怨 的分配self.y,并希望它是Optionalor None

如果我同意并将该行更改为self.y: Optional[int] = None,则 mypy 会抱怨 的返回值do,因为self.y可能是None.

我找到的唯一方法是在使用之前添加 as assert self.y,如:assert self.y is not None,mypy 选择并理解。然而,用许多断言开始每个方法是相当困难的。我有很多这样的值,通常有一个方法可以初始化所有这些值,所有其他方法都在它之后运行。

我知道 mypy 抱怨是理所当然的(该方法do可以在之前调用fill_values),但即使我试图阻止它,我也无法让 mypy 接受这一点。我可以通过添加更多功能来扩展此示例,但 mypy 无法推断出这一点:

from typing import Optional

class Foo:
    def __init__(self, x: int):
        self.x = x
        self.y: int = None  # will initialize later, but I know it will be an int

    def fill_values(self):
        self.y = x**2

    def check_values(self):
        assert self.y is not None

    def do(self) -> int:
        if self.y is None:
            self.fill_values()
        self.check_values()
        return self.x + self.y
Run Code Online (Sandbox Code Playgroud)

有没有更优雅的解决方案的想法,即多个断言语句和Optional类型使代码变得模糊?

Ror*_*van 15

我发现这对我有用:

class Foo:
def __init__(self, x: int):
    self.x = x
    self.y: int # Give self.y a type but no value

def fill_values(self):
    self.y = self.x**2

def do(self) -> int:
    return self.x + self.y
Run Code Online (Sandbox Code Playgroud)

本质上,您所做的就是告诉 mypyself.y当(并且如果)它被初始化时它将是一个整数。尝试self.y在初始化之前调用会引发错误,您可以使用 来检查它是否已初始化hasattr(self, "y")