How do I call setattr() on the current module?
我应该将什么作为第一个参数"object传递给函数setattr(object, name, value)以在当前模块上设置变量?
例如:
1
| setattr(object,"SOME_CONSTANT", 42); |
具有与以下相同的效果:
在包含这些行的模块中(使用正确的object)。
我在模块级别动态生成了几个值,由于我无法在模块级别定义__getattr__,所以这是我的回退。
1 2 3 4 5
| import sys
thismodule = sys.modules[__name__]
setattr(thismodule, name, value) |
或者,不使用setattr(打破了问题的字母,但满足相同的实际目的;-):
注:在模块范围内,后者相当于:
这有点简洁,但不适用于函数内部(vars()给出了它调用的作用域的变量:在全局作用域调用时模块的变量,然后可以使用r/w,但在函数中调用时函数的变量,然后必须将其视为r/o——python联机文档可以有点confusing关于这个特定的区别)。
- 文档给出了有关修改vars()的警告。docs.python.org/library/functions.html_vars。什么时候可以这样做?
- @~unutbu,我不会说这很"好",但是当你在模块级范围而不是在函数内部调用vars()时,它会起作用。
- 谢谢你的信息,@mike。有没有一个简单的方法来理解为什么vars()的行为是这样的(在模块级是可以的,但在函数中没有)?是设计上的限制,还是别的什么?
- vars()在模块范围内等价于globals()(因此返回一个真正的、可修改的dict),而在函数范围内等价于locals()(因此返回一个永不修改的伪dict)。我在模块范围内使用vars(),因为它保存了3个字符、1个音节,而在该范围内使用了它的同义词globals();-)
- 好吧,那很有用,@alex;谢谢。但是为什么函数作用域的locals()应该返回一个永不修改的伪dict?在这里公开一个可修改的dict会有什么问题吗?
- 是的,它会破坏python编译器所做的最重要的优化:函数的局部变量不保存在dict中,它们位于一个紧密的值向量中,并且每个局部变量访问都使用该向量中的索引,而不是名称查找。为了击败优化,迫使您想要存在的dict,从exec ''开始函数:给一个函数计时,每种方法都有几个实质的循环,您将看到这个核心优化对Python性能的重要性。
- 嗯,有什么理由我不能只做globals()[name] = value,记住"这一直是当前模块的字典",在你的答案中vars()等同于globals()?这样做安全吗?
- @Matt,当然,它是安全的(vars和globals在模块顶层是等效的,如果您在函数中,它是globals您无论如何都要用来设置模块级变量)。虽然您可以使用setattr,但正如您在这个问题中选择的那样,您也可以使用相关的索引分配获得相同的效果。顺便说一下,你也可以有一个__getattr__,关于什么行为就像一个模块(可以导入等),但是,我想这是另一个问题。
- @亚历克斯·马泰利:由于我无法在这里向你传达信息,也许你可以看看stackoverflow.com/questions/2447353/getattr-on-a-module,这对我很有意思。
- @亚历克斯:非常感谢你的启发性回答。
- 美胜于丑。显式优于隐式。简单胜于复杂。可读性计数。特殊情况不足以打破规则。应该有一种——最好只有一种——显而易见的方法来做到这一点。如果实现很难解释,那是个坏主意。
- @MSW,我想你忘了"实用胜过纯洁";-)。
- @Matt,啊,是的,@h&229;Vard在那个问题中的解决方案就是我所想的(最初我自己在食谱上发表了它,当我看到它被如此给予时,我投了赞成票);———它在import *之后不起作用,我把它看作是import *的无数问题之一,而不是在有问题的解决方案中;它不适用于裸名(在当前的模块"如您所说")是正确的,但是裸名与限定名完全不同,不应该期望如此。
- 公平的原则,那么除了"它节省3个字符,一个音节"之外,vars()[name] = value的实际情况是什么?它的特殊性足以打破规则,含蓄,不可读,难以解释,并且很大程度上取决于具体实施的知识。是的,它很聪明,C构造的i++-++j也很聪明,如果它恰好按照您希望的方式在您的平台上工作,还有什么真正重要的吗?请注意,这个所谓的实际例子对一个聪明、感兴趣的读者有多大的解释。
- @MSW,哦,我以为你是在评论我的几条评论(关于locals()实际上不能成为一条口述),而不是12小时前的一条——当你不提供参考时很难跟踪。EDOCX1[1]没有什么含蓄或不可读的地方,它不是特别聪明,它在不同平台上都能统一工作,唯一让人困惑的是它在在线文档中记录错误。我想我会编辑答案来指出这一点,因为这似乎真的让你走到了最深处;-)。
- @MSW:你在说什么?
- @马特:假设您的问题是一个诚实的问题——我对Python不太熟悉,并且被PEP20"Python禅"原则所吸引,这些原则使编写良好的Python代码看起来几乎是微不足道的。我发现过度使用__setattr__显然非常诱人,但却会使代码变得神秘。元语法结构的过度使用往往会使代码读取变得困难,这正是C预处理器由于过去的滥用而被避免的原因。
- @MSW:好了,现在你的评论有意义了。我很高兴它能起作用,亚历克斯的描述消除了我的困惑。然而,我可以看到,拥有vars()和globals(),甚至事实上globals()是一个误导性的名字……不理想,但谁在数呢?
如果必须在模块内设置模块范围的变量,那么global有什么问题?
1 2 3 4 5
| # my_module.py
def define_module_scoped_variables():
global a, b, c
a, b, c = 'a', ['b'], 3 |
因此:
1 2 3 4 5 6 7 8
| >>> import my_module
>>> my_module.define_module_scoped_variables()
>>> a
NameError: name 'a' is not defined
>>> my_module.a
'a'
>>> my_module.b
['b'] |
- 我喜欢您演示变量的作用域被约束到模块中。谢谢!
- 是的,我一直(这里"总是"被定义为"最近几个月我一直在学习python")发现global but not really声明令人费解。我想它可能是一个早于模块名称空间的历史遗迹。
- 最初的问题是,如何设置一个属性,该属性的名称由一个字符串给出(与我目前正在搜索的内容相同),所以这样做没有帮助。
在Python3.7中,您将能够在模块级使用__getattr__(相关答案)。
PEP 562:
1 2 3 4
| def __getattr__(name):
if name =="SOME_CONSTANT":
return 42
raise AttributeError(f"module {__name__} has no attribute {name}") |
你不会的,你会的。
您不会。您将动态生成的内容存储在模块以外的其他地方。
- 是的,运行时计算的SOME_CONSTANT并不完全是常量。如果globals()对您不可用,那么您必须访问另一个模块来修改其属性;这必然会让人们感到疑惑。
- 常量和可变变量互斥。常量和动态生成的不是。我正在生成的值总是相同的,并且是基于进一步的"常量"来确定的,这样可以节省算术运算和在我的部分键入内容。