Skip to main content
 首页 » 编程设计

python之使用模块 __getattr__ 时如何回退到默认值

2025年05月04日2198°冷暖

TL;DR:globals()[name] 是退回到“默认”的正确方法吗?

我有一大组从 YML 文件定义的动态创建的类。

动态类创建是通过 PyYAML yaml.safe_load_all 的组合完成的和 dataclasses.make_dataclass (new in 3.7)。我希望这些类的规范偶尔会随着时间而改变,这就是为什么我选择 YML 作为一种易于理解的格式来描述它们的原因。

Python 3.7 引入了新功能 ( see PEP 562 ):一个用于管理模块属性访问的模块级 __getattr__ 函数(还有一个模块级 __dir__ 函数).使用这个新函数允许从模块命名空间导入每个动态创建的 dataclass 类会很方便,如下所示:

# some_module.py 
from package_name import DataClassName1, DataClassName2 

...像这样:

# package_name/__init__ 
from .my_dataclasses import DynamicDataClassesDict 
 
def __getattr__(name): 
    try: 
        return DynamicDataClassesDict[name] 
    except KeyError: 
        # fall back on default module attribute lookup 

在阅读 PEP 562 时,我并没有立即清楚如何退回到模块属性访问的默认功能。对于类,只需调用 super().__getattr__(*args)。我确实在其中一个示例中看到了这一行:

return globals()[f"_deprecated_{name}"] 

这种方法似乎有效。 globals()[name] 是回到“默认”的正确方法吗?它似乎不是,因为 globals()[name] 将引发 KeyError 而不是预期的 AttributeError。

请您参考如下方法:

你把它倒过来了。模块级 __getattr__ 函数仅作为最后手段调用。没有什么可以回退 - 所有其他机制都已经无法找到该名称的属性。

例如,如果你的模块定义了一个全局的foo变量并且有人访问了your_module.foo,那么__getattr__甚至不会被调用.

PEP 在 specification 中解释了这一点:

If an attribute is not found on a module object through the normal lookup (i.e. object.__getattribute__), then __getattr__ is searched in the module __dict__ before raising an AttributeError.

因此,正确的“回退行为”是引发 AttributeError。