How to Create Module-Wide Variables in Python

How to create module-wide variables in Python?

Here is what is going on.

First, the only global variables Python really has are module-scoped variables. You cannot make a variable that is truly global; all you can do is make a variable in a particular scope. (If you make a variable inside the Python interpreter, and then import other modules, your variable is in the outermost scope and thus global within your Python session.)

All you have to do to make a module-global variable is just assign to a name.

Imagine a file called foo.py, containing this single line:

X = 1

Now imagine you import it.

import foo
print(foo.X) # prints 1

However, let's suppose you want to use one of your module-scope variables as a global inside a function, as in your example. Python's default is to assume that function variables are local. You simply add a global declaration in your function, before you try to use the global.

def initDB(name):
global __DBNAME__ # add this line!
if __DBNAME__ is None: # see notes below; explicit test for None
__DBNAME__ = name
else:
raise RuntimeError("Database name has already been set.")

By the way, for this example, the simple if not __DBNAME__ test is adequate, because any string value other than an empty string will evaluate true, so any actual database name will evaluate true. But for variables that might contain a number value that might be 0, you can't just say if not variablename; in that case, you should explicitly test for None using the is operator. I modified the example to add an explicit None test. The explicit test for None is never wrong, so I default to using it.

Finally, as others have noted on this page, two leading underscores signals to Python that you want the variable to be "private" to the module. If you ever do an import * from mymodule, Python will not import names with two leading underscores into your name space. But if you just do a simple import mymodule and then say dir(mymodule) you will see the "private" variables in the list, and if you explicitly refer to mymodule.__DBNAME__ Python won't care, it will just let you refer to it. The double leading underscores are a major clue to users of your module that you don't want them rebinding that name to some value of their own.

It is considered best practice in Python not to do import *, but to minimize the coupling and maximize explicitness by either using mymodule.something or by explicitly doing an import like from mymodule import something.

EDIT: If, for some reason, you need to do something like this in a very old version of Python that doesn't have the global keyword, there is an easy workaround. Instead of setting a module global variable directly, use a mutable type at the module global level, and store your values inside it.

In your functions, the global variable name will be read-only; you won't be able to rebind the actual global variable name. (If you assign to that variable name inside your function it will only affect the local variable name inside the function.) But you can use that local variable name to access the actual global object, and store data inside it.

You can use a list but your code will be ugly:

__DBNAME__ = [None] # use length-1 list as a mutable

# later, in code:
if __DBNAME__[0] is None:
__DBNAME__[0] = name

A dict is better. But the most convenient is a class instance, and you can just use a trivial class:

class Box:
pass

__m = Box() # m will contain all module-level values
__m.dbname = None # database name global in module

# later, in code:
if __m.dbname is None:
__m.dbname = name

(You don't really need to capitalize the database name variable.)

I like the syntactic sugar of just using __m.dbname rather than __m["DBNAME"]; it seems the most convenient solution in my opinion. But the dict solution works fine also.

With a dict you can use any hashable value as a key, but when you are happy with names that are valid identifiers, you can use a trivial class like Box in the above.

Accessing module level variables, from within a function in the module

Just change the function definition to:

def load():
global var # this line has been added to the original code
var = something()

Global variables are read-only from sibling methods. More accurately unless a variable is specified as global, Python consider it as local, but a read access to a local variable name will reach module-level scope if the name is not present in local scope.

See also use of “global” keyword in python and the doc for more details about the global statement

Are there module level variables in Python?

When you do from .config import *, you are importing a copy of limit from config into your own namespace. The limit entity that resides in config is not the same as the one you import. They reside in their own respective namespaces and are independent of each other.

As a workaround for this, consider this example:

A.py

foo = 5

def print_foo():
print(foo)

B.py

import A

A.foo = 10
A.print_foo()

Now, running B.py should give:

$ python B.py
10

Meaning, you can refer to the same variable by prepending the namespace qualifier.

For relative imports, you'd do something similar:

app/
__init__.py
A.py
B.py

In B.py, you'd call import app.A. You'd then refer to the variable as app.A.limit.

Writing to module-wide variable

In b.py, you are setting b.py's myvar. You want to access a's value of myvar. So b.py might look like:

import a
import c

a.myvar = 'b' # belongs to a
myvar = 'something different' # belongs to b
c.pr()

And you need to update c.py so that it uses a.py's myvar, not it's own local copy. So c.py:

import a

def pr():
print a.myvar

Why?

In your original c.py, when you call from a import myvar, this is equivalent to:

import a
myvar = a.myvar

This makes a local version of myvar in c.py upon import. If this is confusing, I found this article about how python variables work very informative.

What is a module variable vs. a global variable?

There are basically 3 different kinds of scope in Python:

  • module scope (saves attributes in the modules __dict__)
  • class/instance scope (saves attributes in the class or instance __dict__)
  • function scope

(maybe I forgot something there ...)

These work almost the same, except that class scopes can dynamically use __getattr__ or __getattribute__ to simulate the presence of a variable that does not in fact exist. And functions are different because you can pass variables to (making them part of their scope) and return them from functions.

However when you're talking about global (and local scope) you have to think of it in terms of visibility. There is no total global scope (except maybe for Pythons built-ins like int, zip, etc.) there is just a global module scope. That represents everything you can access in your module.

So at the beginning of your file this "roughly" represents the module scopes:

Sample Image

Then you import my_module as m that means that m now is a reference to my_module and this reference is in the global scope of your current file. That means 'm' in globals() will be True.

Sample Image

You also define foo=1 that makes foo part of your global scope and 'foo' in globals() will be True. However this foo is a total different entity from m.foo!

Sample Image

Then you do m.bar = m.foo + 1 that access the global variable m and changes its attribute bar based on ms attribute foo. That doesn't make ms foo and bar part of the current global scope. They are still in the global scope of my_module but you can access my_modules global scope through your global variable m.

Sample Image

I abbreviated the module names here with A and B but I hope it's still understandable.

How to make a cross-module variable?

I don't endorse this solution in any way, shape or form. But if you add a variable to the __builtin__ module, it will be accessible as if a global from any other module that includes __builtin__ -- which is all of them, by default.

a.py contains

print foo

b.py contains

import __builtin__
__builtin__.foo = 1
import a

The result is that "1" is printed.

Edit: The __builtin__ module is available as the local symbol __builtins__ -- that's the reason for the discrepancy between two of these answers. Also note that __builtin__ has been renamed to builtins in python3.

How to initialize module-level variables in Python with a method?

Python and Java are fundamentally very different languages, with Python being much more like a scripting language than compiled (even though it does get compiled on-the-fly). Also, Python doesn't really have quite the concept of "an unchanging variable...", at least not by variable name. Variable names are essentially pointers to any type of data (see: dynamic typing) and without some special python decorators you can always change the value of a variable, sometimes quite to your detriment.

More to your point though, because of its scripting nature (and that it can be executed interactively), the order of things matters:

>>> def test():
... print x
...
>>> test()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 2, in test
NameError: global name 'x' is not defined
>>> x = 1
>>> test()
1
>>>

In this case, the global x in the function test is just a pointer and it doesn't matter that x doesn't exist yet because you haven't tried to run test. This might seem counter-intuitive when coming from a strongly-typed and compiled language, but it allows for a lot of nice things like dynamic imports that will only load modules as the functions are used:

>>> def dyn_import():
... import random
... for i in xrange(5):
... print random.random()
...
>>> random.random()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'random' is not defined
>>> dyn_import()
0.246957404578
0.302236192705
0.614960539467
0.0928052533036
0.389804554563
>>> random.random()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'random' is not defined

If every variable needed to be fully defined before being used inside a function, then defining dyn_import would fail unless random was loaded and it was understood what random.random() means. In this case, it is not loaded until the function is actually executed. Additionally, since the function does not put the module into the global namespace of the script, the module is discarded as soon as the function is finished.

It's just one example of how this can be very beneficial, although a pretty important one.



Related Topics



Leave a reply



Submit