我想定义一个辅助函数,它能够从周围的上下文修改模块级变量(具有已知名称),而无需显式传递它,例如。
# mod1.py
mod_var = 1
modify_var()
# mod_var modified
print mod_var
问题是 - 我不能通过mod1.mod_var
引用变量,因为我想在许多模块中使用辅助函数(辅助器本身将在其他模块中定义);它应该从周围的调用上下文/范围中动态“选择”mod_var。
这可能吗?如何获得这个?
我的用例是增强定义网址 - >在Django中查看映射。这些定义分布在定义urlpatterns
模块级变量的许多子模块中。 Helper函数应从调用它的模块中选择此变量并进行修改。避免明确地将其作为参数传递将是很好的。
修改 如需其他解决方案 - 请查看this answer。
EDIT2:
以下错误的解决方案!(留待评论中的参考资料)
最近我找到了另一种解决方案(在我看来最不神奇;))
modify_var()
函数可以像这样实现:
def modify_var():
calling_module = __import__("__main__")
calling_module.mod_var = 42
然而,潜在的利润是有争议的。
unittest
模块在其main
方法中使用此技术。
答案 0 :(得分:4)
你想做的事听起来太神奇了。传入urlpatterns并完成它。明确比隐含更好。
答案 1 :(得分:4)
这是一个真正糟糕,可怕和糟糕的想法,这将导致未来的维护噩梦。然而,如果你真的坚持的话,Python确实提供了“足够的绳索射击你自己的脚”,内省和元编程工具主要用于调试目的,但可能被滥用来执行你非常渴望的错误构想的任务。 / p>
例如,在evil.py
:
import inspect
def modify_var():
callersframe = inspect.stack()[1][0]
callersglobals = callersframe.f_globals
if 'mod_var' not in callersglobals:
raise ValueError, 'calling module has no "mod_var"!'
callersglobals['mod_var'] += 1
现在说你有两个模块,a.py
:
import evil
mod_var = 23
evil.modify_var()
print 'a mod_var now:', mod_var
和b.py
:
import evil
mod_var = 100
evil.modify_var()
print 'b mod_var now:', mod_var
你可以这样做:
$ python -c'import a; import b'
a mod_var now: 24
b mod_var now: 101
然而,在未来保持这种黑魔法技巧会非常令人头疼,所以我强烈建议不以这种方式做事。< / p>
答案 2 :(得分:2)
好的,这是魔术,但我再次建议不要使用它:
import sys
def modify_var():
"""Mysteriously change `mod_var` in the caller's context."""
f = sys._getframe(1)
f.f_locals['mod_var'] += " (modified)"
mod_var = "Hello"
modify_var()
print mod_var
打印:
Hello (modified)
作为对此技术的进一步警告:_getframe
是Python的其他实现不提供的那些函数之一,并且文档包括以下句子:“此函数应仅用于内部和专门用途。“
答案 3 :(得分:0)
如果确实想要这样做,那么你需要在另一个模块或直接在函数中导入mod1,然后从导入中修改它。但是不要这样做;经验丰富的程序员会指出并大笑。