Basics, import.
With your favorite text editor, write a Python module called
mymod.py
, which exports three top-level names:
A countLines(name)
function that reads an input file
and counts the number of lines in it (hint:
file.readlines()
does most of the work for
you)
A countChars(name)
function
that reads an input file and counts the number of characters in it
(hint: file.read()
returns a single
string)
A test(name)
function
that calls both counting functions with a given input
filename
A filename string should be passed into all three
mymod
functions. Now, test your module
interactively, using import
and name qualification
to fetch your exports. Does your PYTHONPATH
include the directory where you created mymod.py
? Try running your module on itself: e.g.,
test("mymod.py")
. Note that
test
opens the file twice; if you’re feeling
ambitious, you might be able to improve this by passing an open file
object into the two count functions.
from/from. Test
your mymod
module from Exercise 1
interactively, by using from
to load the exports directly, first by name, then using the
from*
variant to fetch everything.
__main__. Now, add
a line in your mymod
module that calls the
test
function automatically only when the module
is run as a script. Try running your module from
the system command line; then import the module and test its
functions interactively. Does it still work in both modes?
Nested imports.
Finally, write a second module, myclient.py,
which imports mymod
and tests its functions; run
myclient from the system command line. If
myclient uses from
to fetch
from mymod
, will
mymod
’s functions be
accessible from the top level of myclient? What
if it imports with import
instead? Try coding both
variations in myclient and test interactively,
by importing myclient and inspecting its __
dict
__.
Reload. Experiment with module reloads:
perform the tests in the changer.py
example,
changing the called function’s message and/or behavior
repeatedly, without stopping the Python interpreter. Depending on
your system, you might be able to edit changer
in
another window, or suspend the Python interpreter and edit in the
same window (on Unix, a Ctrl-Z key combination usually suspends the
current process, and a fg
command later resumes
it).
Circular imports
(and other acts of cruelty).[43] In the section on recursive import gotchas, importing
recur1
raised an error. But if we restart Python
and import recur2
interactively, the error
doesn’t occur: test and see this for yourself. Why do you think
it works to import recur2
, but not
recur1
? (Hint: Python stores new modules in the
built-in sys.modules
table (a dictionary) before
running their code; later imports fetch the module from this table
first, whether the module is “complete” yet or not.) Now
try running recur1
as a script:
%
python
recur1.py
. Do you get the same error that occurs
when recur1
is imported interactively? Why? (Hint:
when modules are run as programs they aren’t imported, so this
case has the same effect as importing recur2
interactively; recur2
is the first module
imported.) What happens when you run recur2
as a
script?
[43] We should note that circular imports are extremely rare in practice. In fact, we have never coded or come across a circular import in six years of Python coding—except on the Internet (where such things receive an inordinate amount of attention), and when writing books like this. On the other hand, if you can understand why it’s a potential problem, you know a lot about Python’s import semantics.