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

Ric*_*ica 1 python attributes module python-3.7

TL; DR:globals()[name]CORRECT 是否可以回归到"默认"?

我有一大堆动态创建的类,它们是从YML文件定义的.

动态类创建是通过PyYAMLyaml.safe_load_alldataclasses.make_dataclass(3.7中的新增功能)的组合完成的.我希望这些类的规范偶尔会随着时间而改变,这就是为什么我选择YML作为一种易于理解的格式来描述它们.

Python 3.7引入了新功能(参见PEP 562):__getattr__用于管理模块属性访问的模块级__dir__功能(还有一个模块级功能).利用这个新函数可以方便地dataclass从模块名称空间导入每个动态创建的类,如下所示:

# some_module.py
from package_name import DataClassName1, DataClassName2
Run Code Online (Sandbox Code Playgroud)

......并且像这样:

# package_name/__init__
from .my_dataclasses import DynamicDataClassesDict

def __getattr__(name):
    try:
        return DynamicDataClassesDict[name]
    except KeyError:
        # fall back on default module attribute lookup
Run Code Online (Sandbox Code Playgroud)

在阅读PEP 562时,我不清楚如何回退到模块属性访问的默认功能.对于一个班级,人们只会打电话super().__getattr__(*args).我确实在其中一个例子中看到了这一行:

return globals()[f"_deprecated_{name}"]
Run Code Online (Sandbox Code Playgroud)

这种方法似乎有效.是globals()[name]回落到"默认"的正确方法?它似乎并不是,因为它globals()[name]会提高KeyError而不是预期AttributeError.

Ara*_*Fey 5

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

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

PEP在规范中解释了这一点:

如果通过正常查找(即object.__getattribute__)在模块对象上找不到属性,则在引发AttributeError之前__getattr__在模块中搜索__dict__该属性.

因此,正确的"回退行为"是引发AttributeError.

  • @RickTeachey:肯定有些方法不方便,但它是`__getattr__`系统工作的方式(而不仅仅是模块`__getattr__`).在调用`__getattr__`之前,原始的AttributeError和traceback被[无条件地丢弃](https://github.com/python/cpython/blob/v3.7.0b2/Objects/typeobject.c#L6445).(模块`__getattr__`通过[不同的代码路径](https://github.com/python/cpython/blob/v3.7.0b2/Objects/moduleobject.c#L679),但该代码路径不允许你也使用默认的AttributeError.) (2认同)