On to module details; as mentioned earlier, the sys
and os
modules form the core of much of Python’s
system-related tool set. Let’s now take a quick, interactive tour
through some of the tools in these two modules before applying them in
bigger examples. We’ll start with sys
, the smaller of the two; remember that
to see a full list of all the attributes in sys
, you need to pass it to the dir
function (or see where we did so earlier
in this chapter).
Like most modules, sys
includes both informational names and
functions that take action. For instance, its attributes give us the
name of the underlying operating system on which the platform code
is running, the largest possible integer on this machine, and the
version number of the Python interpreter running our code:
C:...PP3ESystem>python
>>>import sys
>>>sys.platform, sys.maxint, sys.version
('win32', 2147483647, '2.4 (#60, Nov 30 2004, 11:49:19) [MSC v.1310 32 bit (Intel)]') >>> >>>if sys.platform[:3] == 'win': print 'hello windows'
... hello windows
If you have code that must act differently on different
machines, simply test the sys.platform
string as done here; although
most of Python is cross-platform, nonportable tools are usually
wrapped in if
tests like the one
here. For instance, we’ll see later that today’s program launch and
low-level console interaction tools vary per platform—simply test
sys.platform
to pick the right
tool for the machine on which your script is running.
The sys
module also lets us
inspect the module search path both interactively and within a Python program.
sys.path
is a list of strings
representing the true search path in a running Python interpreter.
When a module is imported, Python scans this list from left to
right, searching for the module’s file on each directory named in
the list. Because of that, this is the place to look to verify that
your search path is really set as intended.[*]
The sys.path
list is simply
initialized from your PYTHONPATH
setting—the content of any .pth path files
located in Python’s directories on your machine plus system
defaults—when the interpreter is first started up. In fact, if you
inspect sys.path
interactively,
you’ll notice quite a few directories that are not on your PYTHONPATH
—sys.path
also includes an indicator for
the script’s home directory (an empty string—something I’ll explain
in more detail after we meet os.getcwd
) and a set of standard library
directories that may vary per installation:
>>>sys.path
['', 'C:\PP3rdEd\Examples', ...plus standard paths deleted... ]
Surprisingly, sys.path
can
actually be changed by a program, too. A script
can use list operations such as append
, del
, and the like to configure the search
path at runtime to include all the source directories to which it
needs access. Python always uses the current sys.path
setting to import, no matter what
you’ve changed it to:
>>>sys.path.append(r'C:mydir')
>>>sys.path
['', 'C:\PP3rdEd\Examples', ...more deleted..., 'C:\mydir']
Changing sys.path
directly
like this is an alternative to setting your PYTHONPATH
shell variable, but not a very
good one. Changes to sys.path
are
retained only until the Python process ends, and they must be remade
every time you start a new Python program or session. However, some
types of programs (e.g., scripts that run on a web server) may not
be able to depend on PYTHONPATH
settings; such scripts can instead configure sys.path
on startup to include all the
directories from which they will need to import modules.
The sys
module also
contains hooks into the interpreter; sys.modules
, for example, is a dictionary
containing one name:module
entry for
every module imported in your Python session or program (really, in
the calling Python process):
>>>sys.modules
{'os.path': <module 'ntpath' from 'C:Program FilesPythonLib tpath.pyc'>,... >>>sys.modules.keys( )
['os.path', 'os', 'exceptions', '_ _main_ _', 'ntpath', 'strop', 'nt', 'sys', '_ _builtin_ _', 'site', 'signal', 'UserDict', 'string', 'stat'] >>>sys
<module 'sys' (built-in)> >>>sys.modules['sys']
<module 'sys' (built-in)>
We might use such a hook to write programs that display or
otherwise process all the modules loaded by a program (just iterate
over the keys list of sys.modules
). sys
also exports tools for getting an
object’s reference count used by Python’s garbage collector
(getrefcount
), checking which
modules are built into this Python (builtin_module_names
), and more.
Some of the sys
module’s attributes allow us to fetch all the information related to
the most recently raised Python exception. This is handy if we want
to process exceptions in a more generic fashion. For instance, the sys.exc_info
function returns the latest
exception’s type, value, and traceback object:
>>>try:
...raise IndexError
...except:
...print sys.exc_info( )
... (<class exceptions.IndexError at 7698d0>, <exceptions.IndexError instance at 797140>, <traceback object at 7971a0>)
We might use such information to format our own error message
to display in a GUI pop-up window or HTML web page (recall that by
default, uncaught exceptions terminate programs with a Python error
display). The first two items returned by this call have reasonable
string displays when printed directly, and the third is a traceback
object that can be processed with the standard traceback
module:
>>>import traceback, sys
>>>def grail(x):
...raise TypeError, 'already got one'
... >>>try:
...grail('arthur')
...except:
...exc_info = sys.exc_info( )
...print exc_info[0]
...print exc_info[1]
...traceback.print_tb(exc_info[2])
... exceptions.TypeError already got one File "<stdin>", line 2, in ? File "<stdin>", line 2, in grail
The traceback
module can
also format messages as strings and route them to specific file
objects; see the Python library manual for more details.
I should make two portability notes. First, the most recent exception type, value, and traceback objects are also available via other names:
>>>try:
...raise TypeError, "Bad Thing"
...except:
...print sys.exc_type, sys.exc_value
... exceptions.TypeError Bad Thing
But these names represent a single, global exception, and
they are not specific to a particular thread (threads are covered
in Chapter 5). If you mean to
raise and catch exceptions in multiple threads, exc_info
provides thread-specific
exception details. In fact, you are better off using exc_info
in all cases today, as the
older tools are now documented as deprecated and may be removed in
a future version of Python.
It has also been suggested (in the 2.4 library reference manual and the Python 3.0 PEP document) that string-based exceptions may be removed in a future Python release. This seems more radical and less certain. But if you want to avoid potential future work, use class-based exceptions instead. Because they allow you to define categories of exceptions, they are better than strings in terms of code maintenance anyhow; by listing categories, your exception handlers are immune to future changes. Built-in exceptions have been classes since Python 1.5.
The sys
module
exports additional tools that we will meet in the context of larger
topics and examples introduced later in this chapter and book. For
instance:
Command-line arguments show up as a list of strings called
sys.argv
.
Standard streams are available as sys.stdin
, sys.stdout
, and sys.stderr
.
Program exit can be forced with sys.exit
calls.
Since all of these lead us to bigger topics, though, we will cover them in sections of their own.
[*] It’s not impossible that Python sees PYTHONPATH
differently than you do. A
syntax error in your system shell configuration files may botch
the setting of PYTHONPATH
,
even if it looks fine to you. On Windows, for example, if a
space appears around the =
of
a DOS set command in your autoexec.bat file
(e.g., set NAME = VALUE
), you
will actually set NAME
to an
empty string, not to VALUE
!
18.221.163.13