Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/290.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/xslt/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 将mypy与实例属性的延迟初始化一起使用_Python_Mypy_Python Typing - Fatal编程技术网

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

Python 将mypy与实例属性的延迟初始化一起使用,python,mypy,python-typing,Python,Mypy,Python Typing,更新:尝试检查/填充另一个函数中的值 我试图在我的项目中使用mypy,但我使用的许多实例属性仅在\uuuu init\uuuu之后初始化,而不是在它内部初始化。但是,我确实希望保持在\uuuu init\uuuu声明所有实例属性的良好做法,因此我需要一些复杂的解决方案来实现这一点 我希望这一行为的示例(目前mypy正在抱怨): 目前,mypy抱怨分配了self.y,希望它是可选的或无 如果我同意并将行更改为self.y:Optional[int]=None,那么mypy会抱怨do的返回值,因为

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


我试图在我的项目中使用mypy,但我使用的许多实例属性仅在
\uuuu init\uuuu
之后初始化,而不是在它内部初始化。但是,我确实希望保持在
\uuuu init\uuuu
声明所有实例属性的良好做法,因此我需要一些复杂的解决方案来实现这一点

我希望这一行为的示例(目前mypy正在抱怨):

目前,mypy抱怨分配了
self.y
,希望它是
可选的

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

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

我知道mypy有理由抱怨(方法
do
可以在
fill\u 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

有没有想过一个更优雅的解决方案,即多个断言语句和模糊代码的
可选
类型?

请记住,在
Foo.fill\u值之前调用
Foo.do
是完全可能的,我更喜欢使用
可选[int]
类型,然后,如果
self.y
未初始化为整数,则从
do
引发异常,例如

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”)

检查它是否已初始化。如果
self.y
没有合理的默认值,如果在
填充值之前调用
do
,您会怎么做?您可能希望通过引发异常将此决定传递回调用位置?我已经更新了问题以反映该选项,但mypy仍在抱怨您可以通过尾随的
#键入:ignore[assignment]
注释忽略错误的赋值,或者,您可以通过传递完全关闭此行为,但在所描述的@dspencer这样的情况下,您将失去none检查。至于选项的验证:
mypy
只理解直接断言,当你把它们放在一个单独的方法中时就不理解了,因为推理变得太麻烦了。如果我有很多变量,这就变得麻烦了。此外,您的建议并没有使mypy沉默,因为它仍然认为
self.y
可能是空的,即使在调用
self.fill\u values()
之后也是如此。我更新了问题以反映这一点。你是对的,我现在删除了这个选项,因为mypy的静态分析在那时不知道
self.y
是否已经初始化。太棒了!它还解决了“通信”的问题,即
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