【发布时间】:2018-03-21 16:56:24
【问题描述】:
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。
【问题讨论】:
-
我还没有安装 Python 3.7,但是如果获取模块属性就像从其他对象获取它们一样,您应该能够使用支持可选
default参数的getattr()如果属性不存在,这将是返回值。据我所知,PEP 562 没有讨论新模块__getattr__()是否可以与内置的getattr()函数一起使用,但我希望是这样。 -
@martineau 我还没有尝试过,但
getattr()可能适用于包含__getattr__功能的模块 - 但我不希望它适用于不支持的模块,它也可能对__getattr__不知道的对象视而不见。 -
Rick:如果你打算使用 Python 3.7,你不能假设所有模块都会有它(适用于那个版本)吗?如果没有,可能有一些方法可以测试是否有。我这么说是因为我认为使用
getattr()将是最“pythonic”的方式来做你想做的事。 -
@martineau 如果我正确阅读 PEP,我觉得只有明确定义
__getattr__的模块才有它。我主要是想了解他的新功能是如何工作的。在这一点上,我自己的代码让我满意。 -
Rick:在问题
__getattr__on a module 下,有显示如何在早期版本中执行此操作的答案。就我个人而言,我一直很喜欢sys.modules[]中的模块被常规类的实例替换的那个。
标签: python module attributes python-3.7