【问题标题】:How to get module variable in function from another module?如何从另一个模块获取函数中的模块变量?
【发布时间】:2010-01-10 19:00:15
【问题描述】:

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

# mod1.py
mod_var = 1
modify_var()
# mod_var modified
print mod_var

问题是 - 我无法通过mod1.mod_var 引用变量,因为我想跨多个模块使用辅助函数(辅助函数本身将在其他模块中定义);它应该从周围的调用上下文/范围中动态“选择” mod_var。

这可能吗?这个怎么获得?

我的用例是在 Django 中增强定义 URL -> 视图映射。这些定义分布在许多定义urlpatterns 模块级变量的子模块中。辅助函数应该从调用它的模块中选择这个变量并修改它。避免明确地将其作为参数传递会很好。

编辑: 如需其他解决方案 - 请查看 this 答案。


编辑2:

以下错误解决方案!(留作 cmets 参考)

最近我找到了另一种解决方案(我认为最不神奇的 ;)) modify_var() 函数可以这样实现:

def modify_var():
    calling_module = __import__("__main__")
    calling_module.mod_var = 42

不过,潜在的利润还是值得商榷的。

unittest 模块在其main 方法中使用了这种技术。

【问题讨论】:

    标签: python django


    【解决方案1】:

    这是一个非常糟糕、可怕和可怕的想法,这将导致未来的维护噩梦。但是,如果您真的坚持,Python 确实提供了“足够的绳索来击中自己的脚”:内省和元编程工具主要用于调试目的,但可能被滥用来执行您如此迫切渴望的构思不周的任务。

    例如在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
    

    不过,日后维持这种黑魔法会很头疼,所以我强烈建议不要这样做。

    【讨论】:

    • 我的第二次编辑(有问题)的解决方案是否具有足够低的魔法级别? ;) 仍然存在缺乏明确性的问题。
    • @gorsky,您的第二个解决方案(相当明确且非魔法)没有做任何事情,甚至 接近 您在 Q 中所说的想要做的事情: 它总是修改主模块中的 var,not 在调用模块中!只需尝试使用我在答案中显示的 ab 模块,如果这对您来说并不完全显而易见。
    • 你是对的——我测试错了:像python a.py 这样调用它会使a.py 成为主模块,因此可以按我的意愿工作。错误的假设,感谢您向我澄清。
    【解决方案2】:

    你想做的事情听起来太神奇了。传入 urlpatterns 并完成它。显式优于隐式。

    【讨论】:

    • 恐怕你是对的,但我会等一些魔术师看看他们的把戏;)
    【解决方案3】:

    好的,这就是魔法,但我还是建议不要使用它:

    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 的其他实现不提供的那些函数之一,并且文档包括这句话:“这个函数应该仅用于内部和专门目的。”

    【讨论】:

    • 它有效,但它确实太神奇了。不过谢谢,我会明确地通过它。我被 Python 的禅宗所启发。
    【解决方案4】:

    如果您真的想要这样做,那么您需要在其他模块中或直接在函数中导入 mod1,然后在该导入中对其进行修改。但不要那样做;经验丰富的程序员会指指点点笑。

    【讨论】:

    • 我不能这样做,因为我不知道我的函数会在哪个模块中被调用(几个模块带有urlpatterns变量)。
    猜你喜欢
    • 1970-01-01
    • 2011-04-01
    • 2016-09-30
    • 1970-01-01
    • 2020-12-30
    • 2019-03-07
    • 2016-05-15
    相关资源
    最近更新 更多