如何从另一个模块获取模块变量?

时间:2010-01-10 19:00:16

标签: python django

我想定义一个辅助函数,它能够从周围的上下文修改模块级变量(具有已知名称),而无需显式传递它,例如。

# 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方法中使用此技术。

4 个答案:

答案 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,然后从导入中修改它。但是不要这样做;经验丰富的程序员会指出并大笑。