See Section 18.8
for the exercises.
Basics, import. This one is simpler than you may
think. When you're done, your file and interaction
should look close to the following code (file
mymod.py); remember that Python can read a whole
file into a string or lines list, and the len
built-in returns the length of strings and lists: def countLines(name):
file = open(name, 'r')
return len(file.readlines( ))
def countChars(name):
return len(open(name, 'r').read( ))
def test(name): # Or pass file object
return countLines(name), countChars(name) # Or return a dictionary
% python
>>> import mymod
>>> mymod.test('mymod.py')
(10, 291) On Unix, you can verify your output with a wc command; on Windows,
right-click on your file to views its properties. But note that your
script may report fewer characters than Windows does—for
portability, Python converts Windows \r\n line-end
markers to \n, thereby dropping one byte
(character) per line. To match byte counts with Windows exactly, you
have to open in binary mode (rb) or add back the
number of lines. Incidentally, to do the "ambitious"
part (passing in a file object, so you only open the file once),
you'll probably need to use the
seek method of the built-in file object. We
didn't cover it in the text, but it works just like
C's fseek call (and calls it
behind the scenes): seek resets the current
position in the file to an offset passed in. After a
seek, future input/output operations are relative
to the new position. To rewind to the start of a file without closing
and reopening, call file.seek(0); the file
read methods all pick up at the current position
in the file, so you need to rewind to reread. Here's
what this tweak would look like: def countLines(file):
file.seek(0) # Rewind to start of file.
return len(file.readlines( ))
def countChars(file):
file.seek(0) # Ditto (rewind if needed)
return len(file.read( ))
def test(name):
file = open(name, 'r') # Pass file object.
return countLines(file), countChars(file) # Open file only once.
>>> import mymod2
>>> mymod2.test("mymod2.py")
(11, 392) from/from*. Here's the
from* part. Replace * with
countChars to do the rest. % python
>>> from mymod import *
>>> countChars("mymod.py")
291 __main__. If you code it properly, it works in
either mode (program run or module import): def countLines(name):
file = open(name, 'r')
return len(file.readlines( ))
def countChars(name):
return len(open(name, 'r').read( ))
def test(name): # Or pass file object
return countLines(name), countChars(name) # Or return a dictionary
if __name__ == '__main__':
print test('mymod.py')
% python mymod.py
(13, 346) Nested imports. Here is our solution (file
myclient.py): from mymod import countLines, countChars
print countLines('mymod.py'), countChars('mymod.py')
% python myclient.py
13 346 As for the rest of this one:
mymod's functions are accessible
(that is, importable) from the top level of
myclient, since from simply
assigns to names in the importer (it works almost as though
mymod's defs appeared in
myclient). For example, another file can say this: import myclient
myclient.countLines(...)
from myclient import countChars
countChars(...) If myclient used import instead
of from, you'd need to use a path
to get to the functions in mymod through
myclient: import myclient
myclient.mymod.countLines(...)
from myclient import mymod
mymod.countChars(...) In general, you can define collector modules
that import all the names from other modules, so
they're available in a single convenience module.
Using the following code, you wind up with three different copies of
name somename: mod1.somename,
collector.somename, and __main__.somename; all three share the same integer object
initially, and only the name somename exists at
the interactive prompt as is: #File: mod1.py
somename = 42
#File: collector.py
from mod1 import * # Collect lots of names here.
from mod2 import * # from assigns to my names.
from mod3 import *
>>> from collector import somename Package imports. For this, we put the
mymod.py solution file listed for exercise 3
into a directory package. The following is what we did to set up the
directory and its required __init__.py file in
a Windows console interface; you'll need to
interpolate for other platforms (e.g., use mv and
vi instead of move and
edit). This works in any directory (we just
happened to run our commands in Python's install
directory), and you can do some of this from a file explorer GUI,
too. When we were done, we had a mypkg subdirectory,
which contained files __init__.py and
mymod.py. You need an __init__.py in the mypkg directory, but not
in its parent; mypkg is located in the home
directory component of the module search path. Notice how a
print statement coded in the
directory's initialization file only fires the first
time it is imported, not the second: C:\python22> mkdir mypkg
C:\Python22> move mymod.py mypkg\mymod.py
C:\Python22> edit mypkg\__init__.py
...coded a print statement...
C:\Python22> python
>> import mypkg.mymod
initializing mypkg
>>> mypkg.mymod.countLines('mypkg\mymod.py')
13
>>> from mypkg.mymod import countChars
>>> countChars('mypkg\mymod.py')
346 Reload. This exercise just asks you to
experiment with changing the changer.py example
in the book, so there's nothing to show here. Circular imports. The short story is that
importing recur2 first works, because the
recursive import then happens at the import in
recur1, not at a from in
recur2. The long story goes like this: importing recur2
first works, because the recursive import from
recur1 to recur2 fetches
recur2 as a whole, instead of getting specific
names. recur2 is incomplete when imported from
recur1, but because it uses
import instead of from,
you're safe: Python finds and returns the already
created recur2 module object and continues to run
the rest of recur1 without a glitch. When the
recur2 import resumes, the second
from finds name Y in
recur1 (it's been run
completely), so no error is reported. Running a file as a script is
not the same as importing it as a module; these cases are the same as
running the first import or
from in the script interactively. For instance,
running recur1 as a script is the same as
importing recur2 interactively, since
recur2 is the first module imported in
recur1.
|