Learning Python - Mark Lutz [329]
reload_all(reloadall) # Should reload this, types
To use this utility, import its reload_all function and pass it the name of an already loaded module (like you would the built-in reload function). When the file runs standalone, its self-test code will test itself—it has to import itself because its own name is not defined in the file without an import (this code works in both 3.0 and 2.6 and prints identical output, because we’ve used + instead of a comma in the print):
C:\misc> c:\Python30\python reloadall.py
reloading reloadall
reloading types
Here is this module at work in 3.0 on some standard library modules. Notice how os is imported by tkinter, but tkinter reaches sys before os can (if you want to test this on Python 2.6, substitute Tkinter for tkinter):
>>> from reloadall import reload_all
>>> import os, tkinter
>>> reload_all(os)
reloading os
reloading copyreg
reloading ntpath
reloading genericpath
reloading stat
reloading sys
reloading errno
>>> reload_all(tkinter)
reloading tkinter
reloading _tkinter
reloading tkinter._fix
reloading sys
reloading ctypes
reloading os
reloading copyreg
reloading ntpath
reloading genericpath
reloading stat
reloading errno
reloading ctypes._endian
reloading tkinter.constants
And here is a session that shows the effect of normal versus transitive reloads—changes made to the two nested files are not picked up by reloads, unless the transitive utility is used:
import b # a.py
X = 1
import c # b.py
Y = 2
Z = 3 # c.py
C:\misc> C:\Python30\python
>>> import a
>>> a.X, a.b.Y, a.b.c.Z
(1, 2, 3)
# Change all three files' assignment values and save
>>> from imp import reload
>>> reload(a) # Normal reload is top level only
>>> a.X, a.b.Y, a.b.c.Z (111, 2, 3) >>> from reloadall import reload_all >>> reload_all(a) reloading a reloading b reloading c >>> a.X, a.b.Y, a.b.c.Z # Reloads all nested modules too (111, 222, 333) For more insight, study and experiment with this example on your own; it’s another importable tool you might want to add to your own source code library. Module Design Concepts Like functions, modules present design tradeoffs: you have to think about which functions go in which modules, module communication mechanisms, and so on. All of this will become clearer when you start writing bigger Python systems, but here are a few general ideas to keep in mind: You’re always in a module in Python. There’s no way to write code that doesn’t live in some module. In fact, code typed at the interactive prompt really goes in a built-in module called __main__; the only unique things about the interactive prompt are that code runs and is discarded immediately, and expression results are printed automatically. Minimize module coupling: global variables. Like functions, modules work best if they’re written to be closed boxes. As a rule of thumb, they should be as independent of global variables used within other modules as possible, except for functions and classes imported from them. Maximize module cohesion: unified purpose. You can minimize a module’s couplings by maximizing its cohesion; if all the components of a module share a general purpose, you’re less likely to depend on external names. Modules should rarely change other modules’ variables. We illustrated this with code in Chapter 17, but it’s worth repeating here: it’s perfectly OK to use globals defined in another module (that’s how clients import services, after all), but changing globals in another module is often a symptom of a design problem. There are exceptions, of course, but you should try to communicate results through devices such as function arguments and return values, not cross-module changes. Otherwise, your globals’ values become dependent on the order of arbitrarily remote assignments in other files, and your modules become harder to understand and reuse. As a summary, Figure 24-1 sketches the environment in which modules operate. Modules contain variables, functions, classes, and other modules