Python's global statement and imports in functions

November 1, 2020

Python programmers are familiar with the global statement, which is how Python lets you assign to global variables inside functions (otherwise any variable that's assigned to is assumed to be a local variable). Well, that's not quite what global does.

In languages like C, global variables must exist before you can use them in a function. In common Python usage of global, the variable is created at the module (global) level and then assigned to inside a function, in the rough analog of the C requirement:

aglobal = False
def enable_thing():
  global aglobal
  aglobal = True

There are good reasons to always create the variables at the module level, but Python does not actually require that you do this. You can actually create a new module level variable inside a function using global:

def set_thing():
  global a_new_name
  a_new_name = <something>

(If you read between the lines of the language specification, you can see that this is implied.)

Now, suppose that you want to import a another module as part of initializing some things, but not do it when your module is import'ed (for example, you might be dealing with a module that can be very slow to import). It turns out that you can do this; with global you can import something for module-wide use inside a function. The following works:

def import_slowmodule():
  global slowmodule
  import slowmodule

def use_slowmodule():
  slowmodule.something()

If you do import inside a function, it normally binds the imported name only as a function local thing (as import defines names in the local scope). However, global changes that; when the module's name (or whatever you're importing it as) is set as a global identifier, import binds the name at the module level.

(The actual CPython bytecode does imports in two operations; there is an IMPORT_NAME and then some form of STORE_* bytecode, normally either STORE_FAST or, with a global in effect, STORE_NAME.)

This is sufficiently tricky and clever that if you need to use it, I think you should put a big comment at the top of the file to explain that there is a module that is conditionally imported at the module level that is not visible in your normal import list. Otherwise, sooner or later someone is going to get rather confused (and it may be a future you).


Comments on this page:

By Ben Hutchings at 2020-11-02 21:48:33:

This also works for definitions with `def`, and presumably also with `class`. Those are probably only good for obfuscation though.

Written on 01 November 2020.
« A gotcha with combining single-label and multi-label Prometheus metrics
Fixing blank Cinnamon sessions in VMWare virtual machines (on Fedora) »

Page tools: View Source, View Normal, Add Comment.
Search:
Login: Password:
Atom Syndication: Recent Comments.

Last modified: Sun Nov 1 23:45:57 2020
This dinky wiki is brought to you by the Insane Hackers Guild, Python sub-branch.