将 mypy 与实例属性的惰性初始化一起使用
Using mypy with with lazy initialization of instance attributes
UPDATE:尝试 check/fill 另一个函数中的值
我正在尝试在我的项目中使用 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
目前 mypy 抱怨 self.y
的分配,并希望它是 Optional
或 None
.
如果我同意并将行更改为 self.y: Optional[int] = None
,那么 mypy 会抱怨 do
的 return 值,因为 self.y
可能是 None
.
我发现的唯一方法是在使用 self.y
之前添加 as assert,例如: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
有没有更优雅的解决方案,多个断言语句和 Optional
类型会混淆代码?
请记住,Foo.do
完全有可能在 Foo.fill_values
之前被调用,我更喜欢使用 Optional[int]
类型,然后从 [=14= 引发异常] 如果 self.y
还没有被初始化为一个整数,例如
from typing import Optional
class UninitializedAttributeError(Exception):
pass
class Foo:
def __init__(self, x: int):
self.x = x
self.y: Optional[int] = None
def fill_values(self):
self.y = x**2
def do(self) -> int:
if self.y is None:
raise UninitializedAttributeError("Foo.y is uninitialized")
return self.x + self.y
我发现这对我有用:
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 = x**2
def do(self) -> int:
return self.x + self.y
基本上你所做的就是告诉 mypy self.y
在(如果)它被初始化时将是一个整数。在初始化之前尝试调用 self.y
会引发错误,您可以使用 hasattr(self, "y")
.
检查它是否已初始化
UPDATE:尝试 check/fill 另一个函数中的值
我正在尝试在我的项目中使用 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
目前 mypy 抱怨 self.y
的分配,并希望它是 Optional
或 None
.
如果我同意并将行更改为 self.y: Optional[int] = None
,那么 mypy 会抱怨 do
的 return 值,因为 self.y
可能是 None
.
我发现的唯一方法是在使用 self.y
之前添加 as assert,例如: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
有没有更优雅的解决方案,多个断言语句和 Optional
类型会混淆代码?
请记住,Foo.do
完全有可能在 Foo.fill_values
之前被调用,我更喜欢使用 Optional[int]
类型,然后从 [=14= 引发异常] 如果 self.y
还没有被初始化为一个整数,例如
from typing import Optional
class UninitializedAttributeError(Exception):
pass
class Foo:
def __init__(self, x: int):
self.x = x
self.y: Optional[int] = None
def fill_values(self):
self.y = x**2
def do(self) -> int:
if self.y is None:
raise UninitializedAttributeError("Foo.y is uninitialized")
return self.x + self.y
我发现这对我有用:
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 = x**2
def do(self) -> int:
return self.x + self.y
基本上你所做的就是告诉 mypy self.y
在(如果)它被初始化时将是一个整数。在初始化之前尝试调用 self.y
会引发错误,您可以使用 hasattr(self, "y")
.