对于类型检查,我可以使用装饰器来检查可选类型的类属性是否被定义以防止 None object has no attribute 错误吗?

问题描述 投票:0回答:0

我有一个代码,其中 Main 类接收 Child 类的实例作为属性。 这些属性类型为可选,因为它们在应用程序启动时未定义,在这种情况下它们会被初始化。

Main 实例的方法在很多地方都依赖于那些 Child 对象的方法和属性。

这是我的代码的一个简化示例:

import typing

class Child():
    def print_foo(self) -> None:
        print("foo")

class Main():
    def __init__(self) -> None:
        self.child: typing.Optional[Child] = None

    def initialise(self) -> None:
        if not self.child:
            self.child = Child()

    def foo(self) -> None:
        self.child.print_foo()

main = Main()
main.initialise()
main.foo()

我正在尝试使用 mypy 在我的应用程序管道中强制执行正确的类型检查。

我的问题是,由于这些子属性是可选的并且最初未定义,mypy 抱怨说

Item "None" of "Optional[Child]" has no attribute "print_foo"  [union-attr]

我可以检查定义相关属性的每个方法,例如

def foo(self) -> None:
    if self.child:
        self.child.print_foo()
    else:
        raise Exception("child not defined")

但我不想这样做,因为那意味着为遇到该问题的每个方法重复此代码,而我的应用程序中有很多。

我尝试解决它的一种方法是使用装饰器:

import typing

def check_defined(func):
    def wrapper(*args, **kwargs):
        _self = args[0]
        if not _self.child:
            raise Exception("child not defined")
        else:
            return func(*args, **kwargs)
    return wrapper

class Child():
    def print_foo(self) -> None:
        print("foo")

class Main():
    def __init__(self) -> None:
        self.child: typing.Optional[Child] = None

    def initialise(self) -> None:
        if not self.child:
            self.child = Child()

    @check_defined
    def foo(self) -> None:
        self.child.print_foo()

main = Main()
main.initialise()
main.foo()

但这不会改变类型检查的结果。

因此我的问题是双重的:

  • 为什么我不能使用这样的装饰器来强制定义属性并修复我的类型检查问题?
  • 在不重复代码的情况下系统地验证可选属性定义的好的解决方案是什么?

谢谢!

python decorator python-decorators mypy typing
© www.soinside.com 2019 - 2024. All rights reserved.