diff --git a/dip2 b/dip2 index 0f4549b..933204f 100644 --- a/dip2 +++ b/dip2 @@ -5,10 +5,10 @@
20 May 2004 -
Copyright © 2000, 2001, 2002, 2003, 2004 Mark Pilgrim +
20 May 2004 +
Copyright © 2000, 2001, 2002, 2003, 2004 Mark Pilgrim
This book lives at http://diveintopython3.org/. If you're reading it somewhere else, you may not have the latest version. -
Table of Contents
Welcome to Python. Let's dive in. In this chapter, you'll install the version of Python that's right for you.
ActivePython is freely downloadable, although it is not open source. It is the IDE I used to learn Python, and I recommend you try it unless you have a specific reason not to. One such reason might be that ActiveState is generally several months behind in updating their ActivePython installer when new version of Python are released. If you absolutely need the latest version of Python and ActivePython is still a version behind as you read this, you'll want to use the second option for installing Python on Windows.
The second option is the “official” Python installer, distributed by the people who develop Python itself. It is freely downloadable and open source, and it is always current with the latest version of Python. -
Here is the procedure for installing ActivePython:
After the installation is complete, close the installer and choose Start->Programs->ActiveState ActivePython 2.2->PythonWin IDE. You'll see something like the following:
-PythonWin 2.2.2 (#37, Nov 26 2002, 10:24:37) [MSC 32 bit (Intel)] on win32. ++PythonWin 2.2.2 (#37, Nov 26 2002, 10:24:37) [MSC 32 bit (Intel)] on win32. Portions Copyright 1994-2001 Mark Hammond (mhammond@skippinet.com.au) - see 'Help/About PythonWin' for further copyright information. ->>> -+>>> +Procedure 1.2. Option 2: Installing Python from Python.org
-
- @@ -355,8 +352,8 @@ see 'Help/About PythonWin' for further copyright information.
After the installation is complete, close the installer and select Start->Programs->Python 2.3->IDLE (Python GUI). You'll see something like the following:
-Python 2.3.2 (#49, Oct 2 2003, 20:02:00) [MSC v.1200 32 bit (Intel)] on win32 ++Python 2.3.2 (#49, Oct 2 2003, 20:02:00) [MSC v.1200 32 bit (Intel)] on win32 Type "copyright", "credits" or "license()" for more information. **************************************************************** @@ -367,14 +364,14 @@ Type "copyright", "credits" or "license()" for more information. **************************************************************** IDLE 1.0 ->>> +>>>1.3. Python on Mac OS X
On Mac OS X, you have two choices for installing Python: install it, or don't install it. You probably want to install it.
Mac OS X 10.2 and later comes with a command-line version of Python preinstalled. If you are comfortable with the command line, you can use this version for the first third of the book. However, the preinstalled version does not come with an XML parser, so when you get to the XML chapter, you'll need to install the full version.
Rather than using the preinstalled version, you'll probably want to install the latest version, which also comes with a graphical interactive shell. -
+Procedure 1.3. Running the Preinstalled Version of Python on Mac OS X
To use the preinstalled version of Python, follow these steps:
@@ -392,15 +389,15 @@ interactive shell.
Try it out: -
+Welcome to Darwin! -[localhost:~] you% python -Python 2.2 (#1, 07/14/02, 23:25:09) +[localhost:~] you% python +Python 2.2 (#1, 07/14/02, 23:25:09) [GCC Apple cpp-precomp 6.14] on darwin Type "help", "copyright", "credits", or "license" for more information. ->>> [press Ctrl+D to get back to the command prompt] -[localhost:~] you% -+>>> [press Ctrl+D to get back to the command prompt] +[localhost:~] you% +Procedure 1.4. Installing the Latest Version of Python on Mac OS X
Follow these steps to download and install the latest version of Python:
@@ -430,30 +427,30 @@ Type "help", "copyright", "credits", or "license" for more information.
The MacPython IDE should display a splash screen, then take you to the interactive shell. If the interactive shell does not appear, select -Window->Python Interactive (Cmd-0). The opening window will look something like this: -
-Python 2.3 (#2, Jul 30 2003, 11:45:28) +Window->Python Interactive (Cmd-0). The opening window will look something like this: ++Python 2.3 (#2, Jul 30 2003, 11:45:28) [GCC 3.1 20020420 (prerelease)] Type "copyright", "credits" or "license" for more information. MacPython IDE 1.0.1 ->>> +>>>Note that once you install the latest version, the pre-installed version is still present. If you are running scripts from the command line, you need to be aware which version of Python you are using. -
Example 1.1. Two versions of Python
-[localhost:~] you% python -Python 2.2 (#1, 07/14/02, 23:25:09) +Example 1.1. Two versions of Python
+[localhost:~] you% python +Python 2.2 (#1, 07/14/02, 23:25:09) [GCC Apple cpp-precomp 6.14] on darwin Type "help", "copyright", "credits", or "license" for more information. ->>> [press Ctrl+D to get back to the command prompt] -[localhost:~] you% /usr/local/bin/python -Python 2.3 (#2, Jul 30 2003, 11:45:28) +>>> [press Ctrl+D to get back to the command prompt] +[localhost:~] you% /usr/local/bin/python +Python 2.3 (#2, Jul 30 2003, 11:45:28) [GCC 3.1 20020420 (prerelease)] on darwin Type "help", "copyright", "credits", or "license" for more information. ->>> [press Ctrl+D to get back to the command prompt] -[localhost:~] you% +>>> [press Ctrl+D to get back to the command prompt] +[localhost:~] you%1.4. Python on Mac OS 9
Mac OS 9 does not come with any version of Python, but installation is very simple, and there is only one choice. -
+Follow these steps to install Python on Mac OS 9:
- @@ -479,69 +476,53 @@ Type "help", "copyright", "credits", or "license" for more information.
The MacPython IDE should display a splash screen, and then take you to the interactive shell. If the interactive shell does not appear, select -Window->Python Interactive (Cmd-0). You'll see a screen like this: -
-Python 2.3 (#2, Jul 30 2003, 11:45:28) +Window->Python Interactive (Cmd-0). You'll see a screen like this: ++Python 2.3 (#2, Jul 30 2003, 11:45:28) [GCC 3.1 20020420 (prerelease)] Type "copyright", "credits" or "license" for more information. MacPython IDE 1.0.1 ->>> +>>>1.5. Python on RedHat Linux
Installing under UNIX-compatible operating systems such as Linux is easy if you're willing to install a binary package. Pre-built binary packages are available for most popular Linux distributions. Or you can always compile from source.
Download the latest Python RPM by going to http://www.python.org/ftp/python/ and selecting the highest version number listed, then selecting the
rpms/directory within that. Then download the RPM with the highest version number. You can install it with the rpm command, as shown here: -Example 1.2. Installing on RedHat Linux 9
-localhost:~$ su - -Password: [enter your root password] -[root@localhost root]# wget http://python.org/ftp/python/2.3/rpms/redhat-9/python2.3-2.3-5pydotorg.i386.rpm -Resolving python.org... done. +Example 1.2. Installing on RedHat Linux 9
+localhost:~$ su - +Password: [enter your root password] +[root@localhost root]# wget http://python.org/ftp/python/2.3/rpms/redhat-9/python2.3-2.3-5pydotorg.i386.rpm +Resolving python.org... done. Connecting to python.org[194.109.137.226]:80... connected. HTTP request sent, awaiting response... 200 OK Length: 7,495,111 [application/octet-stream] ... -[root@localhost root]# rpm -Uvh python2.3-2.3-5pydotorg.i386.rpm -Preparing... ########################################### [100%] +[root@localhost root]# rpm -Uvh python2.3-2.3-5pydotorg.i386.rpm +Preparing... ########################################### [100%] 1:python2.3 ########################################### [100%] -[root@localhost root]# python-Python 2.2.2 (#1, Feb 24 2003, 19:13:11) +[root@localhost root]# python ① +Python 2.2.2 (#1, Feb 24 2003, 19:13:11) [GCC 3.2.2 20030222 (Red Hat Linux 3.2.2-4)] on linux2 Type "help", "copyright", "credits", or "license" for more information. ->>> [press Ctrl+D to exit] -[root@localhost root]# python2.3
-Python 2.3 (#1, Sep 12 2003, 10:53:56) +>>> [press Ctrl+D to exit] +[root@localhost root]# python2.3 ② +Python 2.3 (#1, Sep 12 2003, 10:53:56) [GCC 3.2.2 20030222 (Red Hat Linux 3.2.2-5)] on linux2 Type "help", "copyright", "credits", or "license" for more information. ->>> [press Ctrl+D to exit] -[root@localhost root]# which python2.3
+>>> [press Ctrl+D to exit] +[root@localhost root]# which python2.3 ③ /usr/bin/python2.3 -
-++
- Whoops! Just typing python gives you the older version of Python -- the one that was installed by default. That's not the one you want. +
- At the time of this writing, the newest version is called python2.3. You'll probably want to change the path on the first line of the sample scripts to point to the newer version. +
- This is the complete path of the newer version of Python that you just installed. Use this on the
#!line (the first line of each script) to ensure that scripts are running under the latest version of Python, and be sure to type python2.3 to get into the interactive shell.1.6. Python on Debian GNU/Linux
If you are lucky enough to be running Debian GNU/Linux, you install Python through the apt command. -
Example 1.3. Installing on Debian GNU/Linux
-localhost:~$ su - -Password: [enter your root password] -localhost:~# apt-get install python -Reading Package Lists... Done +Example 1.3. Installing on Debian GNU/Linux
+localhost:~$ su - +Password: [enter your root password] +localhost:~# apt-get install python +Reading Package Lists... Done Building Dependency Tree... Done The following extra packages will be installed: python2.3 @@ -552,8 +533,8 @@ The following NEW packages will be installed: 0 upgraded, 2 newly installed, 0 to remove and 3 not upgraded. Need to get 0B/2880kB of archives. After unpacking 9351kB of additional disk space will be used. -Do you want to continue? [Y/n] Y -Selecting previously deselected package python2.3. +Do you want to continue? [Y/n] Y +Selecting previously deselected package python2.3. (Reading database ... 22848 files and directories currently installed.) Unpacking python2.3 (from .../python2.3_2.3.1-1_i386.deb) ... Selecting previously deselected package python. @@ -562,94 +543,78 @@ Setting up python (2.3.1-1) ... Setting up python2.3 (2.3.1-1) ... Compiling python modules in /usr/lib/python2.3 ... Compiling optimized python modules in /usr/lib/python2.3 ... -localhost:~# exit +localhost:~# exit logout -localhost:~$ python -Python 2.3.1 (#2, Sep 24 2003, 11:39:14) +localhost:~$ python +Python 2.3.1 (#2, Sep 24 2003, 11:39:14) [GCC 3.3.2 20030908 (Debian prerelease)] on linux2 Type "help", "copyright", "credits" or "license" for more information. ->>> [press Ctrl+D to exit] +>>> [press Ctrl+D to exit]1.7. Python Installation from Source
If you prefer to build from source, you can download the Python source code from http://www.python.org/ftp/python/. Select the highest version number listed, download the
.tgzfile), and then do the usual configure, make, make install dance. -Example 1.4. Installing from source
-localhost:~$ su - -Password: [enter your root password] -localhost:~# wget http://www.python.org/ftp/python/2.3/Python-2.3.tgz -Resolving www.python.org... done. +Example 1.4. Installing from source
+localhost:~$ su - +Password: [enter your root password] +localhost:~# wget http://www.python.org/ftp/python/2.3/Python-2.3.tgz +Resolving www.python.org... done. Connecting to www.python.org[194.109.137.226]:80... connected. HTTP request sent, awaiting response... 200 OK Length: 8,436,880 [application/x-tar] ... -localhost:~# tar xfz Python-2.3.tgz -localhost:~# cd Python-2.3 -localhost:~/Python-2.3# ./configure -checking MACHDEP... linux2 +localhost:~# tar xfz Python-2.3.tgz +localhost:~# cd Python-2.3 +localhost:~/Python-2.3# ./configure +checking MACHDEP... linux2 checking EXTRAPLATDIR... checking for --without-gcc... no ... -localhost:~/Python-2.3# make -gcc -pthread -c -fno-strict-aliasing -DNDEBUG -g -O3 -Wall -Wstrict-prototypes +localhost:~/Python-2.3# make +gcc -pthread -c -fno-strict-aliasing -DNDEBUG -g -O3 -Wall -Wstrict-prototypes -I. -I./Include -DPy_BUILD_CORE -o Modules/python.o Modules/python.c gcc -pthread -c -fno-strict-aliasing -DNDEBUG -g -O3 -Wall -Wstrict-prototypes -I. -I./Include -DPy_BUILD_CORE -o Parser/acceler.o Parser/acceler.c gcc -pthread -c -fno-strict-aliasing -DNDEBUG -g -O3 -Wall -Wstrict-prototypes -I. -I./Include -DPy_BUILD_CORE -o Parser/grammar1.o Parser/grammar1.c ... -localhost:~/Python-2.3# make install -/usr/bin/install -c python /usr/local/bin/python2.3 +localhost:~/Python-2.3# make install +/usr/bin/install -c python /usr/local/bin/python2.3 ... -localhost:~/Python-2.3# exit +localhost:~/Python-2.3# exit logout -localhost:~$ which python +localhost:~$ which python /usr/local/bin/python -localhost:~$ python -Python 2.3.1 (#2, Sep 24 2003, 11:39:14) +localhost:~$ python +Python 2.3.1 (#2, Sep 24 2003, 11:39:14) [GCC 3.3.2 20030908 (Debian prerelease)] on linux2 Type "help", "copyright", "credits" or "license" for more information. ->>> [press Ctrl+D to get back to the command prompt] -localhost:~$ +>>> [press Ctrl+D to get back to the command prompt] +localhost:~$1.8. The Interactive Shell
Now that you have Python installed, what's this interactive shell thing you're running?
It's like this: Python leads a double life. It's an interpreter for scripts that you can run from the command line or run like applications, by double-clicking the scripts. But it's also an interactive shell that can evaluate arbitrary statements and expressions. This is extremely useful for debugging, quick hacking, and testing. I even know some people who use the Python interactive shell in lieu of a calculator!
Launch the Python interactive shell in whatever way works on your platform, and let's dive in with the steps shown here: -
Example 1.5. First Steps in the Interactive Shell
->>> 1 + 1+
Example 1.5. First Steps in the Interactive Shell
+>>> 1 + 1 ① 2 ->>> print 'hello world'+>>> print 'hello world' ② hello world ->>> x = 1
->>> y = 2 ->>> x + y +>>> x = 1 ③ +>>> y = 2 +>>> x + y 3 -
-1.9. Summary
You should now have a version of Python installed that works for you.
Depending on your platform, you may have more than one version of Python intsalled. If so, you need to be aware of your paths. If simply typing python on the command line doesn't run the version of Python that you want to use, you may need to enter the full pathname of your preferred version.
Congratulations, and welcome to Python. -
+Chapter 2. Your First Python Program
You know how other books go on and on about programming fundamentals and finally work up to building a complete, working program? Let's skip all that. @@ -657,8 +622,9 @@ Let's skip all that.
Here is a complete, working Python program.
It probably makes absolutely no sense to you. Don't worry about that, because you're going to dissect it line by line. But read through it first and see what, if anything, you can make of it. -
Example 2.1.
-odbchelper.pyIf you have not already done so, you can download this and other examples used in this book.
+Example 2.1.
+odbchelper.pyIf you have not already done so, you can download this and other examples used in this book. +
def buildConnectionString(params): """Build a connection string from a dictionary of parameters. @@ -671,60 +637,35 @@ if __name__ == "__main__": "uid":"sa", \ "pwd":"secret" \ } - print buildConnectionString(myParams)Now run this program and see what happens.
-
- -- - -In the ActivePython IDE on Windows, you can run the Python program you're editing by choosing -File->Run... (Ctrl-R). Output is displayed in the interactive window. - --
- -- - -In the Python IDE on Mac OS, you can run a Python program with -Python->Run window... (Cmd-R), but there is an important option you must set first. Open the -.pyfile in the IDE, pop up the options menu by clicking the black triangle in the upper-right corner of the window, and make sure the Run as __main__ option is checked. This is a per-file setting, but you'll only need to do it once per file. --
-- -- - -On UNIX-compatible systems (including Mac OS X), you can run a Python program from the command line: python -odbchelper.pyThe id="odbchelper.output" output of
odbchelper.pywill look like this:server=mpilgrim;uid=sa;database=master;pwd=secret2.2. Declaring Functions
+ print buildConnectionString(myParams)Now run this program and see what happens. +
+ +
In the ActivePython IDE on Windows, you can run the Python program you're editing by choosing +File->Run... (Ctrl-R). Output is displayed in the interactive window. + + +
In the Python IDE on Mac OS, you can run a Python program with +Python->Run window... (Cmd-R), but there is an important option you must set first. Open the .pyfile in the IDE, pop up the options menu by clicking the black triangle in the upper-right corner of the window, and make sure the Run as __main__ option is checked. This is a per-file setting, but you'll only need to do it once per file. ++ +
On UNIX-compatible systems (including Mac OS X), you can run a Python program from the command line: python odbchelper.pyThe id="odbchelper.output" output of
odbchelper.pywill look like this:server=mpilgrim;uid=sa;database=master;pwd=secret2.2. Declaring Functions
Python has functions like most other languages, but it does not have separate header files like C++ or
interface/implementationsections like Pascal. When you need a function, just declare it, like this: -+def buildConnectionString(params):Note that the keyword
defstarts the function declaration, followed by the function name, followed by the arguments in parentheses. Multiple arguments (not shown here) are separated with commas.Also note that the function doesn't define a return datatype. Python functions do not specify the datatype of their return value; they don't even specify whether or not they return a value. -In fact, every Python function returns a value; if the function ever executes a
returnstatement, it will return that value, otherwise it will returnNone, the Python null value.-
-- -- - -In Visual Basic, functions (that return a value) start with -function, and subroutines (that do not return a value) start withsub. There are no subroutines in Python. Everything is a function, all functions return a value (even if it'sNone), and all functions start withdef. -The argument,
params, doesn't specify a datatype. In Python, variables are never explicitly typed. Python figures out what type a variable is and keeps track of it internally.-
- -- - In Java, C++, and other statically-typed languages, you must specify the datatype of the function return value and each function argument. +In fact, every Python function returns a value; if the function ever executes a returnstatement, it will return that value, otherwise it will returnNone, the Python null value. ++ +
In Visual Basic, functions (that return a value) start with function, and subroutines (that do not return a value) start withsub. There are no subroutines in Python. Everything is a function, all functions return a value (even if it'sNone), and all functions start withdef. +The argument,
params, doesn't specify a datatype. In Python, variables are never explicitly typed. Python figures out what type a variable is and keeps track of it internally. ++ +
In Java, C++, and other statically-typed languages, you must specify the datatype of the function return value and each function argument. In Python, you never explicitly specify the datatype of anything. Based on what value you assign, Python keeps track of the datatype internally. - - -2.2.1. How Python's Datatypes Compare to Other Programming Languages
An erudite reader sent me this explanation of how Python compares to other programming languages: -
+
- statically typed language
- A language in which types are fixed at compile time. Most statically typed languages enforce this by requiring you to declare @@ -743,32 +684,21 @@ In fact, every Python function returns a value; if the function ever executes a
So Python is both dynamically typed (because it doesn't use explicit datatype declarations) and strongly typed (because once a variable has a datatype, it actually matters).
2.3. Documenting Functions
You can document a Python function by giving it a
docstring. -Example 2.2. Defining the
buildConnectionStringFunction'sdocstring+Example 2.2. Defining the
buildConnectionStringFunction'sdocstringdef buildConnectionString(params): """Build a connection string from a dictionary of parameters. Returns string."""Triple quotes signify a multi-line string. Everything between the start and end quotes is part of a single string, including carriage returns and other quote characters. You can use them anywhere, but you'll see them most often used when defining a
docstring. --
+- -- - -Triple quotes are also an easy way to define a string with both single and double quotes, like -qq/.../in Perl. -+ +
Triple quotes are also an easy way to define a string with both single and double quotes, like qq/.../in Perl.Everything between the triple quotes is the function's
docstring, which documents what the function does. Adocstring, if it exists, must be the first thing defined in a function (that is, the first thing after the colon). You don't technically -need to give your function adocstring, but you always should. I know you've heard this in every programming class you've ever taken, but Python gives you an added incentive: thedocstringis available at runtime as an attribute of the function.-
+need to give your function a- -- - -Many Python IDEs use the -docstringto provide context-sensitive documentation, so that when you type a function name, itsdocstringappears as a tooltip. This can be incredibly helpful, but it's only as good as thedocstrings you write. -docstring, but you always should. I know you've heard this in every programming class you've ever taken, but Python gives you an added incentive: thedocstringis available at runtime as an attribute of the function. ++ +
Many Python IDEs use the docstringto provide context-sensitive documentation, so that when you type a function name, itsdocstringappears as a tooltip. This can be incredibly helpful, but it's only as good as thedocstrings you write. @@ -778,411 +708,252 @@ need to give your function adocstring, but you always should. I kn2.6. Testing Modules
Python modules are objects and have several useful attributes. You can use this to easily test your modules as you write them. Here's an example that uses the
if__name__trick. --if __name__ == "__main__":Some quick observations before you get to the good stuff. First, parentheses are not required around the
ifexpression. Second, theifstatement ends with a colon, and is followed by indented code.-
+- -- - -Like C, Python uses -==for comparison and=for assignment. Unlike C, Python does not support in-line assignment, so there's no chance of accidentally assigning the value you thought you were comparing. -+if __name__ == "__main__":Some quick observations before you get to the good stuff. First, parentheses are not required around the
ifexpression. Second, theifstatement ends with a colon, and is followed by indented code. ++ +
Like C, Python uses ==for comparison and=for assignment. Unlike C, Python does not support in-line assignment, so there's no chance of accidentally assigning the value you thought you were comparing.So why is this particular
ifstatement a trick? Modules are objects, and all modules have a built-in attribute__name__. A module's__name__depends on how you're using the module. If youimportthe module, then__name__is the module's filename, without a directory path or file extension. But you can also run the module directly as a standalone program, in which case__name__will be a special default value,__main__. ->>> import odbchelper ->>> odbchelper.__name__+>>> import odbchelper +>>> odbchelper.__name__'odbchelper'Knowing this, you can design a test suite for your module within the module itself by putting it in this
ifstatement. When you run the module directly,__name__is__main__, so the test suite executes. When you import the module,__name__is something else, so the test suite is ignored. This makes it easier to develop and debug new modules before integrating -them into a larger program.-
- -- - On MacPython, there is an additional step to make the if__name__trick work. Pop up the module's options menu by clicking the black triangle in the upper-right corner of the window, and +them into a larger program. ++ +
-On MacPython, there is an additional step to make the - -if__name__trick work. Pop up the module's options menu by clicking the black triangle in the upper-right corner of the window, and make sure Run as __main__ is checked. -+Further Reading on Importing Modules
-
-- Python Reference Manual discusses the low-level details of importing modules. +
- Python Reference Manual discusses the low-level details of importing modules.
+Chapter 3. Native Datatypes
3.2. Introducing Lists
3.4. Declaring variables
Now that you know something about dictionaries, tuples, and lists (oh my!), let's get back to the sample program from Chapter 2,
odbchelper.py.Python has local and global variables like most other languages, but it has no explicit variable declarations. Variables spring into existence by being assigned a value, and they are automatically destroyed when they go out of scope. -
Example 3.17. Defining the myParams Variable
+Example 3.17. Defining the myParams Variable
if __name__ == "__main__": myParams = {"server":"mpilgrim", \ "database":"master", \ "uid":"sa", \ "pwd":"secret" \ }Notice the indentation. An
ifstatement is a code block and needs to be indented just like a function. -Also notice that the variable assignment is one command split over several lines, with a backslash (“
\”) serving as a line-continuation marker.-
+- -- - -When a command is split among several lines with the line-continuation marker (“ -\”), the continued lines can be indented in any manner; Python's normally stringent indentation rules do not apply. If your Python IDE auto-indents the continued line, you should probably accept its default unless you have a burning reason not to. -Also notice that the variable assignment is one command split over several lines, with a backslash (“
\”) serving as a line-continuation marker. ++ +
When a command is split among several lines with the line-continuation marker (“ \”), the continued lines can be indented in any manner; Python's normally stringent indentation rules do not apply. If your Python IDE auto-indents the continued line, you should probably accept its default unless you have a burning reason not to.Strictly speaking, expressions in parentheses, straight brackets, or curly braces (like defining a dictionary) can be split into multiple lines with or without the line continuation character (“
\”). I like to include the backslash even when it's not required because I think it makes the code easier to read, but that's a matter of style.Third, you never declared the variable myParams, you just assigned a value to it. This is like VBScript without the
option explicitoption. Luckily, unlike VBScript, Python will not allow you to reference a variable that has never been assigned a value; trying to do so will raise an exception.3.4.1. Referencing Variables
-Example 3.18. Referencing an Unbound Variable
>>> x -Traceback (innermost last): +Example 3.18. Referencing an Unbound Variable
>>> x +Traceback (innermost last): File "<interactive input>", line 1, in ? NameError: There is no variable named 'x' ->>> x = 1 ->>> x +>>> x = 1 +>>> x 1You will thank Python for this one day.
3.4.2. Assigning Multiple Values at Once
One of the cooler programming shortcuts in Python is using sequences to assign multiple values at once. -
Example 3.19. Assigning multiple values at once
>>> v = ('a', 'b', 'e') ->>> (x, y, z) = v->>> x +
Example 3.19. Assigning multiple values at once
>>> v = ('a', 'b', 'e') +>>> (x, y, z) = v ① +>>> x 'a' ->>> y +>>> y 'b' ->>> z -'e'--
+>>> z +'e'- -- -
v is a tuple of three elements, and -(x, y, z)is a tuple of three variables. Assigning one to the other assigns each of the values of v to each of the variables, in order. -++
- v is a tuple of three elements, and
(x, y, z)is a tuple of three variables. Assigning one to the other assigns each of the values of v to each of the variables, in order.This has all sorts of uses. I often want to assign names to a range of values. In C, you would use
enumand manually list each constant and its associated value, which seems especially tedious when the values are consecutive. In Python, you can use the built-inrangefunction with multi-variable assignment to quickly assign consecutive values. -Example 3.20. Assigning Consecutive Values
>>> range(7)+
Example 3.20. Assigning Consecutive Values
>>> range(7) ① [0, 1, 2, 3, 4, 5, 6] ->>> (MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY) = range(7)->>> MONDAY
+>>> (MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY) = range(7) ② +>>> MONDAY ③ 0 ->>> TUESDAY +>>> TUESDAY 1 ->>> SUNDAY -6
-- MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, and SUNDAY are the variables you're defining. (This example came from the
calendarmodule, a fun little module that prints calendars, like the UNIX programcal. Thecalendarmodule defines integer constants for days of the week.) +- Now each variable has its value: MONDAY is
0, TUESDAY is1, and so forth.You can also use multi-variable assignment to build functions that return multiple values, simply by returning a tuple of all the values. The caller can treat it as a tuple, or assign the values to individual variables. Many standard Python libraries do this, including the
osmodule, which you'll discuss in Chapter 6. -+Further Reading on Variables
-
- Python Reference Manual shows examples of when you can skip the line continuation character and when you need to use it. +
- Python Reference Manual shows examples of when you can skip the line continuation character and when you need to use it. -
- How to Think Like a Computer Scientist shows how to use multi-variable assignment to swap the values of two variables. +
- How to Think Like a Computer Scientist shows how to use multi-variable assignment to swap the values of two variables.
3.5. Formatting Strings
Python supports formatting values into strings. Although this can include very complicated expressions, the most basic usage is to insert values into a string with the
%splaceholder. --
-- -- - -String formatting in Python uses the same syntax as the -sprintffunction in C. -Example 3.21. Introducing String Formatting
>>> k = "uid" ->>> v = "sa" ->>> "%s=%s" % (k, v)-'uid=sa'
-+ +
String formatting in Python uses the same syntax as the sprintffunction in C. +Example 3.21. Introducing String Formatting
>>> k = "uid" +>>> v = "sa" +>>> "%s=%s" % (k, v) ① +'uid=sa'++
- The whole expression evaluates to a string. The first
%sis replaced by the value of k; the second%sis replaced by the value of v. All other characters in the string (in this case, the equal sign) stay as they are.Note that
(k, v)is a tuple. I told you they were good for something.You might be thinking that this is a lot of work just to do simple string concatentation, and you would be right, except that string formatting isn't just concatenation. It's not even just formatting. It's also type coercion. -
Example 3.22. String Formatting vs. Concatenating
>>> uid = "sa" ->>> pwd = "secret" ->>> print pwd + " is not a good password for " + uid+
Example 3.22. String Formatting vs. Concatenating
>>> uid = "sa" +>>> pwd = "secret" +>>> print pwd + " is not a good password for " + uid ① secret is not a good password for sa ->>> print "%s is not a good password for %s" % (pwd, uid)+>>> print "%s is not a good password for %s" % (pwd, uid) ② secret is not a good password for sa ->>> userCount = 6 ->>> print "Users connected: %d" % (userCount, )
![]()
+>>> userCount = 6 +>>> print "Users connected: %d" % (userCount, ) ③ ④ Users connected: 6 ->>> print "Users connected: " + userCount
-Traceback (innermost last): +>>> print "Users connected: " + userCount ⑤ +Traceback (innermost last): File "<interactive input>", line 1, in ? -TypeError: cannot concatenate 'str' and 'int' objects
-As with
printfin C, string formatting in Python is like a Swiss Army knife. There are options galore, and modifier strings to specially format many different types of values. -Example 3.23. Formatting Numbers
->>> print "Today's stock price: %f" % 50.4625+
Example 3.23. Formatting Numbers
+>>> print "Today's stock price: %f" % 50.4625 ① 50.462500 ->>> print "Today's stock price: %.2f" % 50.4625+>>> print "Today's stock price: %.2f" % 50.4625 ② 50.46 ->>> print "Change since yesterday: %+.2f" % 1.5
+>>> print "Change since yesterday: %+.2f" % 1.5 ③ +1.50 -
-+Further Reading on String Formatting
-
- Python Library Reference summarizes all the string formatting format characters. +
- Python Library Reference summarizes all the string formatting format characters. -
- Effective AWK Programming discusses all the format characters and advanced string formatting techniques like specifying width, precision, and zero-padding. +
- Effective AWK Programming discusses all the format characters and advanced string formatting techniques like specifying width, precision, and zero-padding.
3.6. Mapping Lists
One of the most powerful features of Python is the list comprehension, which provides a compact way of mapping a list into another list by applying a function to each of the elements of the list. -
Example 3.24. Introducing List Comprehensions
>>> li = [1, 9, 8, 4] ->>> [elem*2 for elem in li]+
Example 3.24. Introducing List Comprehensions
>>> li = [1, 9, 8, 4] +>>> [elem*2 for elem in li] ① [2, 18, 16, 8] ->>> li+>>> li ② [1, 9, 8, 4] ->>> li = [elem*2 for elem in li]
->>> li -[2, 18, 16, 8]
--Here are the list comprehensions in the
buildConnectionStringfunction that you declared in Chapter 2:+>>> li = [elem*2 for elem in li] ③ +>>> li +[2, 18, 16, 8]++
- To make sense of this, look at it from right to left. li is the list you're mapping. Python loops through li one element at a time, temporarily assigning the value of each element to the variable elem. Python then applies the function
elem*2and appends that result to the returned list. +- Note that list comprehensions do not change the original list. +
- It is safe to assign the result of a list comprehension to the variable that you're mapping. Python constructs the new list in memory, and when the list comprehension is complete, it assigns the result to the variable. + +
Here are the list comprehensions in the
buildConnectionStringfunction that you declared in Chapter 2:["%s=%s" % (k, v) for k, v in params.items()]First, notice that you're calling the
itemsfunction of the params dictionary. This function returns a list of tuples of all the data in the dictionary. -Example 3.25. The
keys,values, anditemsFunctions>>> params = {"server":"mpilgrim", "database":"master", "uid":"sa", "pwd":"secret"} ->>> params.keys()+
Example 3.25. The
keys,values, anditemsFunctions>>> params = {"server":"mpilgrim", "database":"master", "uid":"sa", "pwd":"secret"} +>>> params.keys() ① ['server', 'uid', 'database', 'pwd'] ->>> params.values()+>>> params.values() ② ['mpilgrim', 'sa', 'master', 'secret'] ->>> params.items()
-[('server', 'mpilgrim'), ('uid', 'sa'), ('database', 'master'), ('pwd', 'secret')]
-- The
valuesmethod returns a list of all the values. The list is in the same order as the list returned bykeys, soparams.values()[n] == params[params.keys()[n]]for all values of n. +- The
itemsmethod returns a list of tuples of the form(key, value). The list contains all the data in the dictionary.Now let's see what
buildConnectionStringdoes. It takes a list,params., and maps it to a new list by applying string formatting to each element. The new list will have the same number of elements asitems()params., but each element in the new list will be a string that contains both a key and its associated value from the params dictionary. -items()Example 3.26. List Comprehensions in
buildConnectionString, Step by Step>>> params = {"server":"mpilgrim", "database":"master", "uid":"sa", "pwd":"secret"} ->>> params.items() +Example 3.26. List Comprehensions in
buildConnectionString, Step by Step>>> params = {"server":"mpilgrim", "database":"master", "uid":"sa", "pwd":"secret"} +>>> params.items() [('server', 'mpilgrim'), ('uid', 'sa'), ('database', 'master'), ('pwd', 'secret')] ->>> [k for k, v in params.items()]+>>> [k for k, v in params.items()] ① ['server', 'uid', 'database', 'pwd'] ->>> [v for k, v in params.items()]
+>>> [v for k, v in params.items()] ② ['mpilgrim', 'sa', 'master', 'secret'] ->>> ["%s=%s" % (k, v) for k, v in params.items()]
-['server=mpilgrim', 'uid=sa', 'database=master', 'pwd=secret']
--
-- -- -
Note that you're using two variables to iterate through the -params.items()list. This is another use of multi-variable assignment. The first element ofparams.items()is('server', 'mpilgrim'), so in the first iteration of the list comprehension, k will get'server'and v will get'mpilgrim'. In this case, you're ignoring the value of v and only including the value of k in the returned list, so this list comprehension ends up being equivalent toparams.. -keys()- -- -
Here you're doing the same thing, but ignoring the value of k, so this list comprehension ends up being equivalent to -params.. -values()- -- -
Combining the previous two examples with some simple string formatting, you get a list of strings that include both the key and value of each element of the dictionary. This looks suspiciously +>>> ["%s=%s" % (k, v) for k, v in params.items()] ③ +['server=mpilgrim', 'uid=sa', 'database=master', 'pwd=secret'] -++
- Note that you're using two variables to iterate through the
params.items()list. This is another use of multi-variable assignment. The first element ofparams.items()is('server', 'mpilgrim'), so in the first iteration of the list comprehension, k will get'server'and v will get'mpilgrim'. In this case, you're ignoring the value of v and only including the value of k in the returned list, so this list comprehension ends up being equivalent toparams.. +keys()- Here you're doing the same thing, but ignoring the value of k, so this list comprehension ends up being equivalent to
params.. +values()- Combining the previous two examples with some simple string formatting, you get a list of strings that include both the key and value of each element of the dictionary. This looks suspiciously like the output of the program. All that remains is to join the elements in this list into a single string. -
+Further Reading on List Comprehensions
-
- Python Tutorial discusses another way to map lists using the built-in
mapfunction. +- Python Tutorial discusses another way to map lists using the built-in
mapfunction. -- Python Tutorial shows how to do nested list comprehensions. +
- Python Tutorial shows how to do nested list comprehensions.
3.7. Joining Lists and Splitting Strings
You have a list of key-value pairs in the form
key=value, and you want to join them into a single string. To join any list of strings into a single string, use thejoinmethod of a string object. --Here is an example of joining a list from the
buildConnectionStringfunction:+ +Here is an example of joining a list from the
buildConnectionStringfunction:return ";".join(["%s=%s" % (k, v) for k, v in params.items()])One interesting note before you continue. I keep repeating that functions are objects, strings are objects... everything is an object. You might have thought I meant that string variables are objects. But no, look closely at this example and you'll see that the string
";"itself is an object, and you are calling itsjoinmethod.The
joinmethod joins the elements of the list into a single string, with each element separated by a semi-colon. The delimiter doesn't -need to be a semi-colon; it doesn't even need to be a single character. It can be any string.-
- -- - joinworks only on lists of strings; it does not do any type coercion. Joining a list that has one or more non-string elements +need to be a semi-colon; it doesn't even need to be a single character. It can be any string. ++ +
-- - joinworks only on lists of strings; it does not do any type coercion. Joining a list that has one or more non-string elements will raise an exception. -Example 3.27. Output of
odbchelper.py>>> params = {"server":"mpilgrim", "database":"master", "uid":"sa", "pwd":"secret"} ->>> ["%s=%s" % (k, v) for k, v in params.items()] +Example 3.27. Output of
odbchelper.py>>> params = {"server":"mpilgrim", "database":"master", "uid":"sa", "pwd":"secret"} +>>> ["%s=%s" % (k, v) for k, v in params.items()] ['server=mpilgrim', 'uid=sa', 'database=master', 'pwd=secret'] ->>> ";".join(["%s=%s" % (k, v) for k, v in params.items()]) +>>> ";".join(["%s=%s" % (k, v) for k, v in params.items()]) 'server=mpilgrim;uid=sa;database=master;pwd=secret'This string is then returned from the
odbchelperfunction and printed by the calling block, which gives you the output that you marveled at when you started reading this chapter.You're probably wondering if there's an analogous method to split a string into a list. And of course there is, and it's called
split. -Example 3.28. Splitting a String
>>> li = ['server=mpilgrim', 'uid=sa', 'database=master', 'pwd=secret'] ->>> s = ";".join(li) ->>> s +Example 3.28. Splitting a String
>>> li = ['server=mpilgrim', 'uid=sa', 'database=master', 'pwd=secret'] +>>> s = ";".join(li) +>>> s 'server=mpilgrim;uid=sa;database=master;pwd=secret' ->>> s.split(";")+>>> s.split(";") ① ['server=mpilgrim', 'uid=sa', 'database=master', 'pwd=secret'] ->>> s.split(";", 1)
-['server=mpilgrim', 'uid=sa;database=master;pwd=secret']
--
- -- - anystring.is a useful technique when you want to search a string for a substring and then work with everything before the substring +>>> s.split(";", 1) ② +['server=mpilgrim', 'uid=sa;database=master;pwd=secret']split(delimiter, 1)++
splitreversesjoinby splitting a string into a multi-element list. Note that the delimiter (“;”) is stripped out completely; it does not appear in any of the elements of the returned list. +splittakes an optional second argument, which is the number of times to split. (“Oooooh, optional arguments...” You'll learn how to do this in your own functions in the next chapter.) ++ +
-- - anystring.is a useful technique when you want to search a string for a substring and then work with everything before the substring (which ends up in the first element of the returned list) and everything after it (which ends up in the second element). -split(delimiter, 1)+Further Reading on String Methods
- Python Knowledge Base answers common questions about strings and has a lot of example code using strings. -
- Python Library Reference summarizes all the string methods. +
- Python Library Reference summarizes all the string methods. -
- Python Library Reference documents the
stringmodule. +- Python Library Reference documents the
stringmodule. -- The Whole Python FAQ explains why
joinis a string method instead of a list method. +- The Whole Python FAQ explains why
joinis a string method instead of a list method.3.7.1. Historical Note on String Methods
@@ -1192,7 +963,7 @@ calledsplit. the oldstringmodule (which still has a lot of useful stuff in it). I use the newjoinmethod exclusively, but you will see code written either way, and if it really bothers you, you can use the oldstring.joinfunction instead.3.8. Summary
The
odbchelper.pyprogram and its output should now make perfect sense. -+def buildConnectionString(params): """Build a connection string from a dictionary of parameters. @@ -1205,10 +976,10 @@ if __name__ == "__main__": "uid":"sa", \ "pwd":"secret" \ } - print buildConnectionString(myParams)-Here is the output of
odbchelper.py:server=mpilgrim;uid=sa;database=master;pwd=secret+ print buildConnectionString(myParams) +Here is the output of
odbchelper.py:server=mpilgrim;uid=sa;database=master;pwd=secretBefore diving into the next chapter, make sure you're comfortable doing all of these things: -
+-
- Using the Python IDE to test expressions interactively @@ -1226,7 +997,7 @@ if __name__ == "__main__":
- Splitting strings into lists and joining lists into strings
+Chapter 4. The Power Of Introspection
This chapter covers one of Python's strengths: introspection. As you know, everything in Python is an object, and introspection is code looking at other modules and functions in memory as objects, getting information about them, and manipulating them. Along the way, you'll define functions with no name, call functions with arguments out of order, and reference @@ -1234,9 +1005,10 @@ functions whose names you don't even know ahead of time.
4.1. Diving In
Here is a complete, working Python program. You should understand a good deal about it just by looking at it. The numbered lines illustrate concepts covered in Chapter 2, Your First Python Program. Don't worry if the rest of the code looks intimidating; you'll learn all about it throughout this chapter. -
Example 4.1.
-apihelper.pyIf you have not already done so, you can download this and other examples used in this book.
-def info(object, spacing=10, collapse=1):![]()
![]()
+
Example 4.1.
+apihelper.pyIf you have not already done so, you can download this and other examples used in this book. +
+def info(object, spacing=10, collapse=1): ① ② ③ """Print methods and docstrings. Takes module, class, list, dictionary, or string.""" @@ -1247,48 +1019,22 @@ def info(object, spacing=10, collapse=1):![]()
- print info.__doc__
--
+- -- -
This module has one function, -info. According to its function declaration, it takes three parameters: object, spacing, and collapse. The last two are actually optional parameters, as you'll see shortly. -- -- -
The -infofunction has a multi-linedocstringthat succinctly describes the function's purpose. Note that no return value is mentioned; this function will be used solely +if __name__ == "__main__": ④ ⑤ + print info.__doc__++
- This module has one function,
info. According to its function declaration, it takes three parameters: object, spacing, and collapse. The last two are actually optional parameters, as you'll see shortly. +- The
infofunction has a multi-linedocstringthat succinctly describes the function's purpose. Note that no return value is mentioned; this function will be used solely for its effects, rather than its value. -- -- -
Code within the function is indented. - -- -- -
The -if __name__trick allows this program do something useful when run by itself, without interfering with its use as a module for other programs. +- Code within the function is indented. +
- The
if __name__trick allows this program do something useful when run by itself, without interfering with its use as a module for other programs. In this case, the program simply prints out thedocstringof theinfofunction. -- -- -
- ifstatements use==for comparison, and parentheses are not required. -ifstatements use==for comparison, and parentheses are not required.The
infofunction is designed to be used by you, the programmer, while working in the Python IDE. It takes any object that has functions or methods (like a module, which has functions, or a list, which has methods) and prints out the functions and theirdocstrings. -Example 4.2. Sample Usage of
apihelper.py>>> from apihelper import info ->>> li = [] ->>> info(li) -append L.append(object) -- append object to end +Example 4.2. Sample Usage of
apihelper.py>>> from apihelper import info +>>> li = [] +>>> info(li) +append L.append(object) -- append object to end count L.count(value) -> integer -- return number of occurrences of value extend L.extend(list) -- extend list by appending list elements index L.index(value) -> integer -- return index of first occurrence of value @@ -1296,70 +1042,44 @@ insert L.insert(index, object) -- insert object before index pop L.pop([index]) -> item -- remove and return item at index (default last) remove L.remove(value) -- remove first occurrence of value reverse L.reverse() -- reverse *IN PLACE* -sort L.sort([cmpfunc]) -- sort *IN PLACE*; if given, cmpfunc(x, y) -> -1, 0, 1By default the output is formatted to be easy to read. Multi-line
docstrings are collapsed into a single long line, but this option can be changed by specifying0for thecollapseargument. If the function names are longer than 10 characters, you can specify a larger value for thespacingargument to make the output easier to read. -Example 4.3. Advanced Usage of
apihelper.py>>> import odbchelper ->>> info(odbchelper) +sort L.sort([cmpfunc]) -- sort *IN PLACE*; if given, cmpfunc(x, y) -> -1, 0, 1By default the output is formatted to be easy to read. Multi-line
docstrings are collapsed into a single long line, but this option can be changed by specifying0for thecollapseargument. If the function names are longer than 10 characters, you can specify a larger value for thespacingargument to make the output easier to read. +Example 4.3. Advanced Usage of
apihelper.py>>> import odbchelper +>>> info(odbchelper) buildConnectionString Build a connection string from a dictionary Returns string. ->>> info(odbchelper, 30) +>>> info(odbchelper, 30) buildConnectionString Build a connection string from a dictionary Returns string. ->>> info(odbchelper, 30, 0) -buildConnectionString Build a connection string from a dictionary +>>> info(odbchelper, 30, 0) +buildConnectionString Build a connection string from a dictionary Returns string.4.2. Using Optional and Named Arguments
Python allows function arguments to have default values; if the function is called without the argument, the argument gets its default value. Futhermore, arguments can be specified in any order by using named arguments. Stored procedures in SQL Server Transact/SQL can do this, so if you're a SQL Server scripting guru, you can skim this part. -
-Here is an example of
info, a function with two optional arguments:+ +Here is an example of
info, a function with two optional arguments:def info(object, spacing=10, collapse=1):spacing and collapse are optional, because they have default values defined. object is required, because it has no default value. If
infois called with only one argument, spacing defaults to10and collapse defaults to1. Ifinfois called with two arguments, collapse still defaults to1.Say you want to specify a value for collapse but want to accept the default value for spacing. In most languages, you would be out of luck, because you would need to call the function with three arguments. But in Python, arguments can be specified by name, in any order. -
Example 4.4. Valid Calls of
info-info(odbchelper)-info(odbchelper, 12)
-info(odbchelper, collapse=0)
-info(spacing=15, object=odbchelper)
-Example 4.4. Valid Calls of
info+info(odbchelper) ① +info(odbchelper, 12) ② +info(odbchelper, collapse=0) ③ +info(spacing=15, object=odbchelper) ④++
- With only one argument, spacing gets its default value of
10and collapse gets its default value of1. +- With two arguments, collapse gets its default value of
1. +- Here you are naming the collapse argument explicitly and specifying its value. spacing still gets its default value of
10. +- Even required arguments (like object, which has no default value) can be named, and named arguments can appear in any order.
This looks totally whacked until you realize that arguments are simply a dictionary. The “normal” method of calling functions without argument names is actually just a shorthand where Python matches up the values with the argument names in the order they're specified in the function declaration. And most of the -time, you'll call functions the “normal” way, but you always have the additional flexibility if you need it.
-
- -- - The only thing you need to do to call a function is specify a value (somehow) for each required argument; the manner and order +time, you'll call functions the “normal” way, but you always have the additional flexibility if you need it. + + +
-The only thing you need to do to call a function is specify a value (somehow) for each required argument; the manner and order in which you do that is up to you. - - -+Further Reading on Optional Arguments
-
- Python Tutorial discusses exactly when and how default arguments are evaluated, which matters when the default value is a list or an expression with side effects. +
- Python Tutorial discusses exactly when and how default arguments are evaluated, which matters when the default value is a list or an expression with side effects.
4.3. Using
@@ -1368,180 +1088,96 @@ time, you'll call functions the “normal” way, but you always have th cough, Visual Basic).type,str,dir, and Other Built-In Functions4.3.1. The
typeFunctionThe
typefunction returns the datatype of any arbitrary object. The possible types are listed in thetypesmodule. This is useful for helper functions that can handle several types of data. -Example 4.5. Introducing
type>>> type(1)+
Example 4.5. Introducing
type>>> type(1) ① <type 'int'> ->>> li = [] ->>> type(li)+>>> li = [] +>>> type(li) ② <type 'list'> ->>> import odbchelper ->>> type(odbchelper)
+>>> import odbchelper +>>> type(odbchelper) ③ <type 'module'> ->>> import types
->>> type(odbchelper) == types.ModuleType -True
-typecan take a variable and return its datatype. +typealso works on modules. +- You can use the constants in the
typesmodule to compare types of objects. This is what theinfofunction does, as you'll see shortly.4.3.2. The
strFunctionThe
strcoerces data into a string. Every datatype can be coerced into a string. -Example 4.6. Introducing
str->>> str(1)+
Example 4.6. Introducing
str+>>> str(1) ① '1' ->>> horsemen = ['war', 'pestilence', 'famine'] ->>> horsemen +>>> horsemen = ['war', 'pestilence', 'famine'] +>>> horsemen ['war', 'pestilence', 'famine'] ->>> horsemen.append('Powerbuilder') ->>> str(horsemen)+>>> horsemen.append('Powerbuilder') +>>> str(horsemen) ② "['war', 'pestilence', 'famine', 'Powerbuilder']" ->>> str(odbchelper)
+>>> str(odbchelper) ③ "<module 'odbchelper' from 'c:\\docbook\\dip\\py\\odbchelper.py'>" ->>> str(None)
-'None'
-- A subtle but important behavior of
stris that it works onNone, the Python null value. It returns the string'None'. You'll use this to your advantage in theinfofunction, as you'll see shortly.At the heart of the
infofunction is the powerfuldirfunction.dirreturns a list of the attributes and methods of any object: modules, functions, strings, lists, dictionaries... pretty much anything. -Example 4.7. Introducing
dir>>> li = [] ->>> dir(li)-['append', 'count', 'extend', 'index', 'insert', +
Example 4.7. Introducing
dir>>> li = [] +>>> dir(li) ① +['append', 'count', 'extend', 'index', 'insert', 'pop', 'remove', 'reverse', 'sort'] ->>> d = {} ->>> dir(d)+>>> d = {} +>>> dir(d) ② ['clear', 'copy', 'get', 'has_key', 'items', 'keys', 'setdefault', 'update', 'values'] ->>> import odbchelper ->>> dir(odbchelper)
-['__builtins__', '__doc__', '__file__', '__name__', 'buildConnectionString']
--
+- -- -
li is a list, so -returns a list of all the methods of a list. Note that the returned list contains the names of the methods as strings, not +>>> import odbchelper +>>> dir(odbchelper) ③ +['__builtins__', '__doc__', '__file__', '__name__', 'buildConnectionString']dir(li)++
- li is a list, so
returns a list of all the methods of a list. Note that the returned list contains the names of the methods as strings, not the methods themselves. -dir(li)- -- -
d is a dictionary, so -returns a list of the names of dictionary methods. At least one of these,dir(d)keys, should look familiar. -- -- -
This is where it really gets interesting. -odbchelperis a module, soreturns a list of all kinds of stuff defined in the module, including built-in attributes, likedir(odbchelper)__name__,__doc__, and whatever other attributes and methods you define. In this case,odbchelperhas only one user-defined method, thebuildConnectionStringfunction described in Chapter 2. -- d is a dictionary, so
returns a list of the names of dictionary methods. At least one of these,dir(d)keys, should look familiar. +- This is where it really gets interesting.
odbchelperis a module, soreturns a list of all kinds of stuff defined in the module, including built-in attributes, likedir(odbchelper)__name__,__doc__, and whatever other attributes and methods you define. In this case,odbchelperhas only one user-defined method, thebuildConnectionStringfunction described in Chapter 2.Finally, the
callablefunction takes any object and returnsTrueif the object can be called, orFalseotherwise. Callable objects include functions, class methods, even classes themselves. (More on classes in the next chapter.) -Example 4.8. Introducing
callable->>> import string ->>> string.punctuation+
Example 4.8. Introducing
callable+>>> import string +>>> string.punctuation ① '!"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~' ->>> string.join+>>> string.join② <function join at 00C55A7C> ->>> callable(string.punctuation)
+>>> callable(string.punctuation) ③ False ->>> callable(string.join)
+>>> callable(string.join) ④ True ->>> print string.join.__doc__
-join(list [,sep]) -> string +>>> print string.join.__doc__ ⑤ +join(list [,sep]) -> string Return a string composed of the words in list, with intervening occurrences of sep. The default separator is a single space. - (joinfields and join are synonymous)
--
- -- -
The functions in the -stringmodule are deprecated (although many people still use thejoinfunction), but the module contains a lot of useful constants like this string.punctuation, which contains all the standard punctuation characters. -- -- -
- string.joinis a function that joins a list of strings. -- -- -
string.punctuation is not callable; it is a string. (A string does have callable methods, but the string itself is not callable.) - -- -- -
- string.joinis callable; it's a function that takes two arguments. -- -- -
Any callable object may have a -docstring. By using thecallablefunction on each of an object's attributes, you can determine which attributes you care about (methods, functions, classes) + (joinfields and join are synonymous)++
- The functions in the
stringmodule are deprecated (although many people still use thejoinfunction), but the module contains a lot of useful constants like this string.punctuation, which contains all the standard punctuation characters. +string.joinis a function that joins a list of strings. +- string.punctuation is not callable; it is a string. (A string does have callable methods, but the string itself is not callable.) +
string.joinis callable; it's a function that takes two arguments. +- Any callable object may have a
docstring. By using thecallablefunction on each of an object's attributes, you can determine which attributes you care about (methods, functions, classes) and which you want to ignore (constants and so on) without knowing anything about the object ahead of time. -4.3.3. Built-In Functions
type,str,dir, and all the rest of Python's built-in functions are grouped into a special module called__builtin__. (That's two underscores before and after.) If it helps, you can think of Python automatically executingfrom __builtin__ import *on startup, which imports all the “built-in” functions into the namespace so you can use them directly.The advantage of thinking like this is that you can access all the built-in functions and attributes as a group by getting information about the
__builtin__module. And guess what, Python has a function calledinfo. Try it yourself and skim through the list now. We'll dive into some of the more important functions later. (Some of the built-in error classes, likeAttributeError, should already look familiar.) -Example 4.9. Built-in Attributes and Functions
>>> from apihelper import info ->>> import __builtin__ ->>> info(__builtin__, 20) -ArithmeticError Base class for arithmetic errors. +Example 4.9. Built-in Attributes and Functions
>>> from apihelper import info +>>> import __builtin__ +>>> info(__builtin__, 20) +ArithmeticError Base class for arithmetic errors. AssertionError Assertion failed. AttributeError Attribute not found. EOFError Read beyond end of file. @@ -1550,215 +1186,119 @@ Exception Common base class for all exceptions. FloatingPointError Floating point operation failed. IOError I/O operation failed. -[...snip...]-
- -- - Python comes with excellent reference manuals, which you should peruse thoroughly to learn all the modules Python has to offer. But unlike most languages, where you would find yourself referring back to the manuals or man pages to remind +[...snip...] + +
-Python comes with excellent reference manuals, which you should peruse thoroughly to learn all the modules Python has to offer. But unlike most languages, where you would find yourself referring back to the manuals or man pages to remind yourself how to use these modules, Python is largely self-documenting. - - -+Further Reading on Built-In Functions
-
- Python Library Reference documents all the built-in functions and all the built-in exceptions. +
- Python Library Reference documents all the built-in functions and all the built-in exceptions.
4.4. Getting Object References With
getattrYou already know that Python functions are objects. What you don't know is that you can get a reference to a function without knowing its name until run-time, by using the
getattrfunction. -Example 4.10. Introducing
getattr>>> li = ["Larry", "Curly"] ->>> li.pop+
Example 4.10. Introducing
getattr>>> li = ["Larry", "Curly"] +>>> li.pop ① <built-in method pop of list object at 010DF884> ->>> getattr(li, "pop")+>>> getattr(li, "pop") ② <built-in method pop of list object at 010DF884> ->>> getattr(li, "append")("Moe")
->>> li +>>> getattr(li, "append")("Moe") ③ +>>> li ["Larry", "Curly", "Moe"] ->>> getattr({}, "clear")
+>>> getattr({}, "clear") ④ <built-in method clear of dictionary object at 00F113D4> ->>> getattr((), "pop")
-Traceback (innermost last): +>>> getattr((), "pop") ⑤ +Traceback (innermost last): File "<interactive input>", line 1, in ? -AttributeError: 'tuple' object has no attribute 'pop'
--
+- -- -
This gets a reference to the -popmethod of the list. Note that this is not calling thepopmethod; that would beli.pop(). This is the method itself. -- -- -
This also returns a reference to the -popmethod, but this time, the method name is specified as a string argument to thegetattrfunction.getattris an incredibly useful built-in function that returns any attribute of any object. In this case, the object is a list, +AttributeError: 'tuple' object has no attribute 'pop'++
- This gets a reference to the
popmethod of the list. Note that this is not calling thepopmethod; that would beli.pop(). This is the method itself. +- This also returns a reference to the
popmethod, but this time, the method name is specified as a string argument to thegetattrfunction.getattris an incredibly useful built-in function that returns any attribute of any object. In this case, the object is a list, and the attribute is thepopmethod. -- -- -
In case it hasn't sunk in just how incredibly useful this is, try this: the return value of -getattris the method, which you can then call just as if you had saidli.append("Moe")directly. But you didn't call the function directly; you specified the function name as a string instead. -- -- -
- getattralso works on dictionaries. -- -- -
In theory, -getattrwould work on tuples, except that tuples have no methods, sogetattrwill raise an exception no matter what attribute name you give. -- In case it hasn't sunk in just how incredibly useful this is, try this: the return value of
getattris the method, which you can then call just as if you had saidli.append("Moe")directly. But you didn't call the function directly; you specified the function name as a string instead. +getattralso works on dictionaries. +- In theory,
getattrwould work on tuples, except that tuples have no methods, sogetattrwill raise an exception no matter what attribute name you give.4.4.1.
getattrwith Modules
getattrisn't just for built-in datatypes. It also works on modules. -Example 4.11. The
getattrFunction inapihelper.py>>> import odbchelper ->>> odbchelper.buildConnectionString+
Example 4.11. The
getattrFunction inapihelper.py>>> import odbchelper +>>> odbchelper.buildConnectionString ① <function buildConnectionString at 00D18DD4> ->>> getattr(odbchelper, "buildConnectionString")+>>> getattr(odbchelper, "buildConnectionString") ② <function buildConnectionString at 00D18DD4> ->>> object = odbchelper ->>> method = "buildConnectionString" ->>> getattr(object, method)
+>>> object = odbchelper +>>> method = "buildConnectionString" +>>> getattr(object, method) ③ <function buildConnectionString at 00D18DD4> ->>> type(getattr(object, method))
+>>> type(getattr(object, method)) ④ <type 'function'> ->>> import types ->>> type(getattr(object, method)) == types.FunctionType +>>> import types +>>> type(getattr(object, method)) == types.FunctionType True ->>> callable(getattr(object, method))
-True
--
+>>> callable(getattr(object, method)) ⑤ +True- -- -
This returns a reference to the -buildConnectionStringfunction in theodbchelpermodule, which you studied in Chapter 2, Your First Python Program. (The hex address you see is specific to my machine; your output will be different.) -- -- -
Using -getattr, you can get the same reference to the same function. In general,is equivalent togetattr(object, "attribute")object.attribute. Ifobjectis a module, thenattributecan be anything defined in the module: a function, class, or global variable. -- -- -
And this is what you actually use in the -infofunction. object is passed into the function as an argument; method is a string which is the name of a method or function. -- -- -
In this case, method is the name of a function, which you can prove by getting its -type. -- -- -
Since method is a function, it is callable. - -++
- This returns a reference to the
buildConnectionStringfunction in theodbchelpermodule, which you studied in Chapter 2, Your First Python Program. (The hex address you see is specific to my machine; your output will be different.) +- Using
getattr, you can get the same reference to the same function. In general,is equivalent togetattr(object, "attribute")object.attribute. Ifobjectis a module, thenattributecan be anything defined in the module: a function, class, or global variable. +- And this is what you actually use in the
infofunction. object is passed into the function as an argument; method is a string which is the name of a method or function. +- In this case, method is the name of a function, which you can prove by getting its
type. +- Since method is a function, it is callable.
4.4.2.
getattrAs a DispatcherA common usage pattern of
getattris as a dispatcher. For example, if you had a program that could output data in a variety of different formats, you could define separate functions for each output format and use a single dispatch function to call the right one.For example, let's imagine a program that prints site statistics in HTML, XML, and plain text formats. The choice of output format could be specified on the command line, or stored in a configuration file. A
statsoutmodule defines three functions,output_html,output_xml, andoutput_text. Then the main program defines a single output function, like this: -Example 4.12. Creating a Dispatcher with
getattr+Example 4.12. Creating a Dispatcher with
getattrimport statsout -def output(data, format="text"):- output_function = getattr(statsout, "output_%s" % format)
- return output_function(data)
-
-- Now you can simply call the output function in the same way as any other function. The output_function variable is a reference to the appropriate function from the
statsoutmodule.Did you see the bug in the previous example? This is a very loose coupling of strings and functions, and there is no error checking. What happens if the user passes in a format that doesn't have a corresponding function defined in
statsout? Well,getattrwill returnNone, which will be assigned to output_function instead of a valid function, and the next line that attempts to call that function will crash and raise an exception. That's bad.Luckily,
getattrtakes an optional third argument, a default value. -Example 4.13.
getattrDefault Values+Example 4.13.
getattrDefault Valuesimport statsout def output(data, format="text"): output_function = getattr(statsout, "output_%s" % format, statsout.output_text) - return output_function(data)-