Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to get module variable in function from another module?

Tags:

python

django

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 Django. 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.

like image 908
gorsky Avatar asked Jan 21 '26 01:01

gorsky


1 Answers

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.

like image 71
Alex Martelli Avatar answered Jan 23 '26 20:01

Alex Martelli



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!