I’ve run into a bit of a wall importing modules in a Python script. I’ll do my best to describe the error, why I run into it, and why I’m tying this particular approach to solve my problem (which I will describe in a second):
Let’s suppose I have a module in which I’ve defined some utility functions/classes, which refer to entities defined in the namespace into which this auxiliary module will be imported (let “a” be such an entity):
def f(): print a
And then I have the main program, where “a” is defined, into which I want to import those utilities:
import module1 a=3 module1.f()
Executing the program will trigger the following error:
Traceback (most recent call last): File "Z:Pythonmain.py", line 10, in <module> module1.f() File "Z:Pythonmodule1.py", line 3, in f print a NameError: global name 'a' is not defined
Similar questions have been asked in the past (two days ago, d’uh) and several solutions have been suggested, however I don’t really think these fit my requirements. Here’s my particular context:
I’m trying to make a Python program which connects to a MySQL database server and displays/modifies data with a GUI. For cleanliness sake, I’ve defined the bunch of auxiliary/utility MySQL-related functions in a separate file. However they all have a common variable, which I had originally defined inside the utilities module, and which is the cursor object from MySQLdb module.
I later realised that the cursor object (which is used to communicate with the db server) should be defined in the main module, so that both the main module and anything that is imported into it can access that object.
End result would be something like this:
def utility_1(args): code which references a variable named "cur" def utility_n(args): etcetera
And my main module:
import MySQLdb, Tkinter db=MySQLdb.connect(#blahblah) ; cur=db.cursor() #cur is defined! from utilities_module import *
And then, as soon as I try to call any of the utilities functions, it triggers the aforementioned “global name not defined” error.
A particular suggestion was to have a “from program import cur” statement in the utilities file, such as this:
from program import cur #rest of function definitions
import Tkinter, MySQLdb db=MySQLdb.connect(#blahblah) ; cur=db.cursor() #cur is defined! from utilities_module import *
But that’s cyclic import or something like that and, bottom line, it crashes too. So my question is:
How in hell can I make the “cur” object, defined in the main module, visible to those auxiliary functions which are imported into it?
Thanks for your time and my deepest apologies if the solution has been posted elsewhere. I just can’t find the answer myself and I’ve got no more tricks in my book.
Globals in Python are global to a module, not across all modules. (Many people are confused by this, because in, say, C, a global is the same across all implementation files unless you explicitly make it
There are different ways to solve this, depending on your actual use case.
Before even going down this path, ask yourself whether this really needs to be global. Maybe you really want a class, with
f as an instance method, rather than just a free function? Then you could do something like this:
import module1 thingy1 = module1.Thingy(a=3) thingy1.f()
If you really do want a global, but it’s just there to be used by
module1, set it in that module.
import module1 module1.a=3 module1.f()
On the other hand, if
a is shared by a whole lot of modules, put it somewhere else, and have everyone import it:
import shared_stuff import module1 shared_stuff.a = 3 module1.f()
… and, in module1.py:
import shared_stuff def f(): print shared_stuff.a
Don’t use a
from import unless the variable is intended to be a constant.
from shared_stuff import a would create a new
a variable initialized to whatever
shared_stuff.a referred to at the time of the import, and this new
a variable would not be affected by assignments to
Or, in the rare case that you really do need it to be truly global everywhere, like a builtin, add it to the builtin module. The exact details differ between Python 2.x and 3.x. In 3.x, it works like this:
import builtins import module1 builtins.a = 3 module1.f()
As a workaround, you could consider setting environment variables in the outer layer, like this.
import os os.environ['MYVAL'] = str(myintvariable)
import os myval = None if 'MYVAL' in os.environ: myval = os.environ['MYVAL']
As an extra precaution, handle the case when MYVAL is not defined inside the module.
A function uses the globals of the module it’s defined in. Instead of setting
a = 3, for example, you should be setting
module1.a = 3. So, if you want
cur available as a global in
A better solution: don’t use globals. Pass the variables you need into the functions that need it, or create a class to bundle all the data together, and pass it when initializing the instance.
This post is just an observation for Python behaviour I encountered. Maybe the advices you read above don’t work for you if you made the same thing I did below.
Namely, I have a module which contains global/shared variables (as suggested above):
#sharedstuff.py globaltimes_randomnode= globalist_randomnode=
Then I had the main module which imports the shared stuff with:
import sharedstuff as shared
and some other modules that actually populated these arrays. These are called by the main module. When exiting these other modules I can clearly see that the arrays are populated. But when reading them back in the main module, they were empty. This was rather strange for me (well, I am new to Python). However, when I change the way I import the sharedstuff.py in the main module to:
from globals import *
it worked (the arrays were populated).
The easiest solution to this particular problem would have been to add another function within the module that would have stored the cursor in a variable global to the module. Then all the other functions could use it as well.
cursor = None def setCursor(cur): global cursor cursor = cur def method(some, args): global cursor do_stuff(cursor, some, args)
import module1 cursor = get_a_cursor() module1.setCursor(cursor) module1.method()
Since globals are module specific, you can add the following function to all imported modules, and then use it to:
- Add singular variables (in dictionary format) as globals for those
- Transfer your main module globals to it
addglobals = lambda x: globals().update(x)
Then all you need to pass on current globals is:
Since I haven’t seen it in the answers above, I thought I would add my simple workaround, which is just to add a
global_dict argument to the function requiring the calling module’s globals, and then pass the dict into the function when calling; e.g:
# external_module def imported_function(global_dict=None): print(global_dict["a"]) # calling_module a = 12 from external_module import imported_function imported_function(global_dict=globals()) 12
The OOP way of doing this would be to make your module a class instead of a set of unbound methods. Then you could use
__init__ or a setter method to set the variables from the caller for use in the module methods.