264

I'm bit confused about how the global variables work. I have a large project, with around 50 files, and I need to define global variables for all those files.

What I did was define them in my projects main.py file, as following:

# ../myproject/main.py

# Define global myList
global myList
myList = []

# Imports
import subfile

# Do something
subfile.stuff()
print(myList[0])

I'm trying to use myList in subfile.py, as following

# ../myproject/subfile.py

# Save "hey" into myList
def stuff():
    globals()["myList"].append("hey")

An other way I tried, but didn't work either

# ../myproject/main.py

# Import globfile    
import globfile

# Save myList into globfile
globfile.myList = []

# Import subfile
import subfile

# Do something
subfile.stuff()
print(globfile.myList[0])

And inside subfile.py I had this:

# ../myproject/subfile.py

# Import globfile
import globfile

# Save "hey" into myList
def stuff():
    globfile.myList.append("hey")

But again, it didn't work. How should I implement this? I understand that it cannot work like that, when the two files don't really know each other (well subfile doesn't know main), but I can't think of how to do it, without using io writing or pickle, which I don't want to do.

martineau
  • 99,260
  • 22
  • 139
  • 249
  • Actually, your second approach works just fine for me. main.py correctly prints out "hey". Can you be more specific on what you me by "it didn't work"? – rodion Oct 23 '12 at 16:01
  • @rodion: importing cycles - the code in subfile tries to import globfile, which in itś body imports itself back – jsbueno Oct 23 '12 at 16:21
  • 1
    `NameError: name 'myList' is not defined` from `main.py` line `print(globfile.myList[0])` –  Oct 23 '12 at 16:38
  • My understanding is that `__init__.py` can also be used to define global variables, is this usage out of date? Should the `config.py` file approach be preferred? – proof_by_accident Nov 19 '20 at 19:12

7 Answers7

383

The problem is you defined myList from main.py, but subfile.py needs to use it. Here is a clean way to solve this problem: move all globals to a file, I call this file settings.py. This file is responsible for defining globals and initializing them:

# settings.py

def init():
    global myList
    myList = []

Next, your subfile can import globals:

# subfile.py

import settings

def stuff():
    settings.myList.append('hey')

Note that subfile does not call init()— that task belongs to main.py:

# main.py

import settings
import subfile

settings.init()          # Call only once
subfile.stuff()         # Do stuff with global var
print settings.myList[0] # Check the result

This way, you achieve your objective while avoid initializing global variables more than once.

Hai Vu
  • 30,982
  • 9
  • 52
  • 84
  • 51
    I like the general approach, but not the whole `init()` stuff. Modules are only evaluated the first time they're imported, so it's perfectly OK to initialize those variables in the body of the module. – Kirk Strauser Oct 23 '12 at 17:10
  • 22
    +1 Kirk: I agree. However, my approach prevent the case where other modules modify globals.myList before the main program starts. – Hai Vu Oct 23 '12 at 20:52
  • 2
    You should call it something other than globals, which is a builtin name. PyLint gives the warning: "Redefining built-in 'globals' (redefined-builtin)" – twasbrillig Jan 27 '15 at 20:29
  • Thanks. Any idea how to remove the “Undefined variable from import” errors that appear in Eclipse PyDev by using this file structure (i.e. importing global variables from settings.py)? I had to [disable the error in PyDev](http://stackoverflow.com/a/32111638/395857), which is not ideal. – Franck Dernoncourt Aug 20 '15 at 07:08
  • @FranckDernoncourt I am sorry, I don't use Eclipse so I am even more clueless than you are. – Hai Vu Aug 20 '15 at 12:10
  • but what if i want to use myList as an interactive variable cross the files, and save the last changes in setting.py for further usage again?! – Mohsen Haddadi Jun 03 '18 at 06:19
  • @MohsenHaddadi then you need to write a file anyways, so just do that at the end and read it in init(). Look at "shelve" for example. – DonQuiKong Nov 15 '18 at 12:50
  • When the subfile.py program already contains statement import settings.py, why do we need to import settings in main.py again? – Nikhil Valiveti Sep 19 '20 at 10:11
128

See Python's document on sharing global variables across modules:

The canonical way to share information across modules within a single program is to create a special module (often called config or cfg).

config.py:

x = 0   # Default value of the 'x' configuration setting

Import the config module in all modules of your application; the module then becomes available as a global name.

main.py:

import config
print (config.x)

or

from config import x
print (x)

In general, don’t use from modulename import *. Doing so clutters the importer’s namespace, and makes it much harder for linters to detect undefined names.

Ogaga Uzoh
  • 1,454
  • 1
  • 8
  • 10
22

You can think of Python global variables as "module" variables - and as such they are much more useful than the traditional "global variables" from C.

A global variable is actually defined in a module's __dict__ and can be accessed from outside that module as a module attribute.

So, in your example:

# ../myproject/main.py

# Define global myList
# global myList  - there is no "global" declaration at module level. Just inside
# function and methods
myList = []

# Imports
import subfile

# Do something
subfile.stuff()
print(myList[0])

And:

# ../myproject/subfile.py

# Save "hey" into myList
def stuff():
     # You have to make the module main available for the 
     # code here.
     # Placing the import inside the function body will
     # usually avoid import cycles - 
     # unless you happen to call this function from 
     # either main or subfile's body (i.e. not from inside a function or method)
     import main
     main.mylist.append("hey")
Morgoth
  • 4,139
  • 5
  • 35
  • 53
jsbueno
  • 77,044
  • 9
  • 114
  • 168
  • 2
    wow, normally one would expect two files importing each other to get into an infinite loop. – Nikhil VJ Aug 24 '18 at 04:11
  • 3
    ha At first glance it looks that way, doesn't it? What happens in the def stuff() is that the import doesn't run when the file loads..it only runs when the stuff() function is called. So starting with main we import subfile and then call subfile.stuff() which then imports main...no loop, just import once in main. See the note in the subfile.py example about import cycles. – John Apr 18 '19 at 18:59
11

Using from your_file import * should fix your problems. It defines everything so that it is globally available (with the exception of local variables in the imports of course).

for example:

##test.py:

from pytest import *

print hello_world

and:

##pytest.py

hello_world="hello world!"
IT Ninja
  • 5,564
  • 9
  • 37
  • 63
  • 4
    Except if you assign to one such variable – jsbueno Oct 23 '12 at 16:03
  • 5
    I personally avoid the use of `import *` at all cost so that references are explicit (and not confusing), Besides, when ever have you actually used all "`*`" references in any module? – ThorSummoner Sep 18 '14 at 20:30
  • 25
    DON'T DO import *. Your global variables will no longer remain in sync. Each module receives its own copy. Changing the variable in one file will not reflect in another. It is also warned against in https://docs.python.org/2/faq/programming.html#how-do-i-share-global-variables-across-modules – Isa Hassen Feb 07 '16 at 14:11
9

Hai Vu answer works great, just one comment:

In case you are using the global in other module and you want to set the global dynamically, pay attention to import the other modules after you set the global variables, for example:

# settings.py
def init(arg):
    global myList
    myList = []
    mylist.append(arg)


# subfile.py
import settings

def print():
    settings.myList[0]


# main.py
import settings
settings.init("1st")     # global init before used in other imported modules
                         # Or else they will be undefined

import subfile    
subfile.print()          # global usage
lastboy
  • 538
  • 4
  • 11
4

Your 2nd attempt will work perfectly, and is actually a really good way to handle variable names that you want to have available globally. But you have a name error in the last line. Here is how it should be:

# ../myproject/main.py

# Import globfile    
import globfile

# Save myList into globfile
globfile.myList = []

# Import subfile
import subfile

# Do something
subfile.stuff()
print(globfile.myList[0])

See the last line? myList is an attr of globfile, not subfile. This will work as you want.

Mike

MikeHunter
  • 3,734
  • 1
  • 16
  • 13
1

I just came across this post and thought of posting my solution, just in case of anyone being in the same situation as me, where there are quite some files in the developed program, and you don't have the time to think through the whole import sequence of your modules (if you didn't think of that properly right from the start, such as I did).

In such cases, in the script where you initiate your global(s), simply code a class which says like:

class My_Globals:
  def __init__(self):
    self.global1 = "initial_value_1"
    self.global2 = "initial_value_2"
    ...

and then use, instead of the line in the script where you initiated your globals, instead of

global1 = "initial_value_1"

use

globals = My_Globals()

I was then able to retrieve / change the values of any of these globals via

globals.desired_global

in any script, and these changes were automatically also applied to all the other scripts using them. All worked now, by using the exact same import statements which previously failed, due to the problems mentioned in this post / discussion here. I simply thought of global object's properties being changing dynamically without the need of considering / changing any import logic, in comparison to simple importing of global variables, and that definitely was the quickest and easiest (for later access) approach to solve this kind of problem for me.

DevelJoe
  • 354
  • 3
  • 12