gpt4 book ai didi

python - 类型检查动态添加的属性

转载 作者:行者123 更新时间:2023-12-04 04:31:18 26 4
gpt4 key购买 nike

编写特定项目时 pytest插件,我经常发现Config用于附加我自己的属性的对象。例子:

from _pytest.config import Config


def pytest_configure(config: Config) -> None:
config.fizz = "buzz"

def pytest_unconfigure(config: Config) -> None:
print(config.fizz)

显然,没有 fizz _pytest.config.Config 中的属性类,所以运行 mypy在上面的代码片段上产生
conftest.py:5: error: "Config" has no attribute "fizz"
conftest.py:8: error: "Config" has no attribute "fizz"

(请注意, pytest 还没有带有类型提示的版本,因此如果您想在本地实际重现错误,请按照 this comment 中的步骤安装一个分支)。

有时重新定义用于类型检查的类可以提供快速帮助:
from typing import TYPE_CHECKING

if TYPE_CHECKING:
from _pytest.config import Config as _Config

class Config(_Config):
fizz: str

else:
from _pytest.config import Config



def pytest_configure(config: Config) -> None:
config.fizz = "buzz"

def pytest_unconfigure(config: Config) -> None:
print(config.fizz)

然而,除了困惑的代码之外,子类化的解决方法非常有限:添加例如
from pytest import Session


def pytest_sessionstart(session: Session) -> None:
session.config.fizz = "buzz"

会迫使我也覆盖 Session用于类型检查。

解决此问题的最佳方法是什么? Config是一个例子,但我通常在每个项目中都有更多(针对测试收集/调用/报告等的项目特定调整)。我可以想象写我自己的版本 pytest stub ,但是我需要为每个项目重复这个,这非常乏味。

最佳答案

这样做的一种方法是设法让您的 Config对象定义 __getattr____setattr__方法。如果这些方法是在类中定义的,mypy 将使用它们来键入检查您正在访问或设置某些未定义属性的位置。

例如:

from typing import Any

class Config:
def __init__(self) -> None:
self.always_available = 1

def __getattr__(self, name: str) -> Any: pass

def __setattr__(self, name: str, value: Any) -> None: pass

c = Config()

# Revealed types are 'int' and 'Any' respectively
reveal_type(c.always_available)
reveal_type(c.missing_attr)

# The first assignment type checks, but the second doesn't: since
# 'already_available' is a predefined attr, mypy won't try using
# `__setattr__`.
c.dummy = "foo"
c.always_available = "foo"

如果您确定您的临时属性始终是 strs 或其他内容,您可以输入 __getattr____setattr__退货或接受 str而不是 Any分别获得更严格的类型。

不幸的是,您仍然需要使用子类型技巧或制作自己的 stub ——这给您带来的唯一优势是您至少不必列出您想要设置的每个自定义属性并制作它可能创造出真正可重用的东西。这可能会使该选项对您来说更可口,但不确定。

您可以探索的其他选项包括:
  • 只需添加一个 # type: ignore对使用临时属性的每一行进行注释。如果是侵入性的,这将是一种有点精确的抑制错误消息的方式。
  • 输入您的 pytest_configurepytest_unconfigure所以他们接受 Any 类型的对象.这将是一种抑制错误消息的侵入性较小的方式。如果你想最小化使用 Any 的爆炸半径,您可以将任何想要使用这些自定义属性的逻辑限制在它们自己的专用函数中并继续使用 Config其他地方。
  • 尝试使用强制转换。例如,内部 pytest_configure你可以做 config = cast(MutableConfig, config)哪里MutableConfig是您编写的子类 _pytest.Config 的类并定义了 __getattr____setattr__ .这可能是上述两种方法之间的中间地带。
  • 如果将 ad-hoc 属性添加到 Config和类似的类是一种常见的事情,也许尝试说服 pytest 维护者包括仅输入 __getattr____setattr__在他们的类型提示中定义——或者让用户添加这些动态属性的一些其他更专用的方式。
  • 关于python - 类型检查动态添加的属性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61213745/

    26 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com