开发者

How to get module variable in function from another module?

I'd like to define a helper function that has the ability to modify a module-level variable (with known name) from surrounding context without explicitly passing it, e.g.

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

The problem is - I can't reference variable by mod1.mod_var, because I want to use helper function across many modules (helper itself will be defined in other module); it should dynamically 'pick' mod_var from surrounding calling context/scope.

Is this possible? How to obtain this?

My use case is to enhance defining URL -> view mapping in D开发者_StackOverflow社区jango. Those definitions are spread across many sub-modules that define urlpatterns module-level variable. Helper function should pick this variable from the module that calls it and modify it. Avoiding explicitly passing it as argument would be great.

Edit: For additional solution - check this answer.


Edit2:

Wrong solution below! (left for references in comments)

Recently I've found another solution (the least magical in my opinion ;)) modify_var() function could be implemented like this:

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

Still, potential profits are arguable.

unittest module uses this technique in its main method.


It's a truly bad, horrible, and awful idea, which will lead to future maintenance nightmares. However, Python does offer "enough rope to shoot yourself in the foot", if you truly insist: introspection and metaprogramming tools which are mostly intended for debugging purposes, but can be abused to perform the ill-conceived task you so desperately crave.

For example, in 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

now say you have two modules, a.py:

import evil

mod_var = 23
evil.modify_var()
print 'a mod_var now:', mod_var

and b.py:

import evil

mod_var = 100
evil.modify_var()
print 'b mod_var now:', mod_var

you could do:

$ python -c'import a; import b'
a mod_var now: 24
b mod_var now: 101

However, maintaining this kind of black-magic tricks in the future is going to be a headache, so I'd strongly recommend not doing things this way.


What you want to do sounds like too much magic. Pass in urlpatterns and be done with it. Explicit is better than implicit.


OK, here's the magic, but again, I recommend not using it:

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

prints:

Hello (modified)

As a further warning against this technique: _getframe is one of those functions that other implementations of Python don't provide, and the docs include this sentence: "This function should be used for internal and specialized purposes only."


If you really want to do that then you'll need to import mod1 in either the other module or directly in the function, and then modify it off that import. But don't do that; seasoned programmers will point and laugh.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜