20

I'm currently learning Python, and I have to work on a Python 2.7 project.

Accessing "module scope" variables in functions of the module itself is a bit confusing for me, and I didn't succeed in finding a satisfying way.

My attempts so far:

Way 1:

my_module.py

my_global_var = None

def my_func():
    global my_global_var
    my_global_var = 'something_else'

Here I think that confusing local and "module scope" vars may be quite easy.

Way 2:

my_module.py

import my_module

my_global_var = None

def my_func():
    my_module.my_global_var = 'something_else'

Here, the name of "my_module" could not be as easily changed as "way 1" when necessary. Plus, importing a module into itself sounds quite weird.

What would you recommend? Or would you suggest something else? Thanks.

ivanleoncz
  • 9,070
  • 7
  • 57
  • 49
Maxime Pacary
  • 22,336
  • 11
  • 85
  • 113
  • 1
    Don't use `Way 2`, use `Way 1`. Python scoping and assignments are interesting. The interpreter will always search for a name from the inner most scope outwards when reading the value from a name. When you assign a value to a name it does so in the current scope. This means if you assign to `my_global_var` without the `global` keyword, your module will have two different `my_global_var`'s from the point of the nested scope assignment and beyond in the nested scope. The global statement is simply telling the interpreter to assign values to the `global` scope for the name `my_global_var`. – Matt Feb 25 '16 at 06:54

4 Answers4

26

You probably want to read up on Python's namespaces. Way 1 is correct but generally unnecessary, never use 2. An easier approach is to just use a dict (or class or some other object):

my_globals = {'var': None}

def my_func():
    my_globals['var'] = 'something else'

Assignments always go into the innermost scope and the innermost scope is always searched first, thus the need for the global keyword. In this case you aren't assigning to a name, so it's unnecessary.

Zach Kelling
  • 52,505
  • 13
  • 109
  • 108
  • 3
    Ah. So dict values can be modified in function scope, but not raw string values. Python seems quite counter-intuitive here. Anyway, this works and suits exactly my need. thanks – Maxime Pacary Jul 27 '11 at 10:19
  • Assignments always go into the innermost scope and are always searched first, thus the need for the `global` keyword. In this case you aren't assigning to a name, so it's unnecessary (Python will search innermost scope, and not finding `my_globals` eventually reach the module-level scope. – Zach Kelling Jul 27 '11 at 10:32
  • Thanks for the detailed explanations on this behavior. I understand better. – Maxime Pacary Jul 27 '11 at 11:56
  • 3
    @FrostyZ You can modify any mutable object without using global keyword. – High schooler Jun 04 '14 at 15:07
  • Thanks for this answer. One question please: so using a dict is good just as long as you don't have any local variables carrying the same name as the dict? Doesn't that mean relying on a convention between the developers that might not be respected? I guess that preventing name clashes with _one_ global variable is a lot better than preventing clashes with an unlimited number of global variables. However, wouldn't it just be better off explicitly declaring `global` before using the variable(s)? – yair May 26 '19 at 05:41
4

Way 1 is the correct way when you absolutely must rebind a global variable. However you should ask yourself why you are modifying a global and whether there is something better you can do (such as encapsulating the behaviour in a class).

Importing a module into itself should be avoided as it is error prone. If the module is also a script you would sometimes need to import __main__ instead, or if the module is part of a package maybe you should be importing foo.my_module. In short, don't do that.

Duncan
  • 92,073
  • 11
  • 122
  • 156
3

Importing a module within itself can have unwanted side effects (like evaluating statements more than once.) I would suggest using "Way 1" and a tool like pylint to help verify your code and enforce common practices.

PyLint can be found at: http://www.logilab.org/project/pylint

Mark Evans
  • 531
  • 4
  • 6
1

Avoid setting globals at all. You can create new namespaces with classes quite easily, so use class variables if you must.

For anything serious you need a proper design with classes anyways.

Jochen Ritzel
  • 104,512
  • 31
  • 200
  • 194
  • 1
    Thanks for your answer. I would like to create a singleton, and the recommended way seems to simply create a module (see http://stackoverflow.com/questions/31875/is-there-a-simple-elegant-way-to-define-singletons-in-python), so I would prefer avoid a class in this particular case. – Maxime Pacary Jul 27 '11 at 10:21
  • @FrostyZ - I'd advise against using the module as a singleton, if for no other reason than it makes unit testing really difficult. See – Mark Evans Jul 27 '11 at 12:04
  • Even for testing, some singletons seem acceptable (e.g. a logger). See http://googletesting.blogspot.com/2008/08/root-cause-of-singletons.html – Maxime Pacary Jul 27 '11 at 12:51