Dave Kuhlman
http://www.rexx.com/~dkuhlman
Email: [email protected]
Release 1.01
July 5, 2006
Copyright (c) 2003 Dave Kuhlman
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Python is a high-level general purpose programming language. Because code is automatically compiled to byte code and executed, Python is suitable for use as a scripting language, Web application implementation language, etc. Because Python can be extended in C and C++, Python can provide the speed needed for even compute intensive tasks.
Some things you will need to know:
if (x) { if (y) { f1() } f2() }
in Python would be:
if x: if y: f1() f2()
And, the convention is to use four spaces (and no tabs) for each level of indentation.
If you execute Python from the command line with no script, Python gives you an interactive prompt. This is an excellent facility for learning Python and for trying small snippets of code. Many of the examples that follow were developed using the Python interactive prompt.
In addition, there are tools that will give you a more powerful and fancy Python interactive mode. One example is IPython, which is available at http://ipython.scipy.org/. You may also want to consider using IDLE. IDLE is a graphical integrated development environment for Python; it contains a Python shell. You will find a script to start up IDLE in the Tools/scripts directory of your Python distribution. IDLE requires Tkinter.
In Python, strings are immutable sequences of characters. They are immutable in that in order to modify a string, you must produce a new string.
Any text information.
Create a new string from a constant:
s1 = 'abce' s2 = "xyz" s3 = """A multi-line string. """
Use any of the string methods, for example:
>>> 'The happy cat ran home.'.upper() 'THE HAPPY CAT RAN HOME.' >>> 'The happy cat ran home.'.find('cat') 10 >>> 'The happy cat ran home.'.find('kitten') -1 >>> 'The happy cat ran home.'.replace('cat', 'dog') 'The happy dog ran home.'
Type "help(str)" or see http://www.python.org/doc/current/lib/string-methods.html for more information on string methods.
You can also use the equivalent functions from the string module. For example:
>>> import string >>> s1 = 'The happy cat ran home.' >>> string.find(s1, 'happy') 4
See http://www.python.org/doc/current/lib/module-string.htmlfor more information on the string module.
There is also a string formatting operator: "%".
>>> state = 'California' >>> 'It never rains in sunny %s.' % state 'It never rains in sunny California.'
You can use any of the following formatting characters:
Conversion | Meaning | Notes |
---|---|---|
d | Signed integer decimal. | |
i | Signed integer decimal. | |
o | Unsigned octal. | (1) |
u | Unsigned decimal. | |
x | Unsigned hexidecimal (lowercase). | (2) |
X | Unsigned hexidecimal (uppercase). | (2) |
e | Floating point exponential format (lowercase). | |
E | Floating point exponential format (uppercase). | |
f | Floating point decimal format. | |
F | Floating point decimal format. | |
g | Same as "e" if exponent is greater than -4 or less than precision, "f" otherwise. | |
G | Same as "E" if exponent is greater than -4 or less than precision, "F" otherwise. | |
c | Single character (accepts integer or single character string). | |
r | String (converts any python object using repr()). | (3) |
s | String (converts any python object using str()). | (4) |
% | No argument is converted, results in a "%" character in the result. |
And these flags:
Flag | Meaning |
---|---|
# | The value conversion will use the ``alternate form'' (where defined below). |
0 | The conversion will be zero padded for numeric values. |
- | The converted value is left adjusted (overrides the "0" conversion if both are given). |
(a space) A blank should be left before a positive number (or empty string) produced by a signed conversion. | |
+ | A sign character ("+" or "-") will precede the conversion (overrides a "space" flag). |
See http://www.python.org/doc/current/lib/typesseq-strings.htmlfor more information on string formatting.
You can also write strings to a file and read them from a file. Here are some examples:
>>> outfile = file('tmp.txt', 'w') >>> outfile.write('This is line #1\n') >>> outfile.write('This is line #2\n') >>> outfile.write('This is line #3\n') >>> outfile.close()
Notes:
>>> infile = file('tmp.txt', 'r') >>> content = infile.read() >>> print content This is line #1 This is line #2 This is line #3 >>> infile.close()
>>> infile = file('tmp.txt', 'r') >>> for line in infile.readlines(): ... print 'Line:', line ... Line: This is line #1 Line: This is line #2 Line: This is line #3 >>> infile.close()
Notes:
>>> infile = file('tmp.txt', 'r') >>> for line in infile: ... print 'Line:', line ...
A few additional comments about strings:
>>> s1 = 'abcd' >>> s1[1] 'b' >>> s1[2] 'c' >>> for ch in s1: ... print ch ... a b c d
names = {'tree': 'sycamore', 'flower': 'poppy', 'herb': 'arugula'} print 'The tree is %(tree)s' % names print 'The flower is %(flower)s' % names print 'The herb is %(herb)s' % names
There are several types of sequences in Python. We've already discussed strings. In this section we will describe lists and tuples. See http://www.python.org/doc/current/lib/typesseq.html for a description of the other sequence types (e.g. buffers and xrange objects).
Lists are dynamic arrays. They are arrays in the sense that you can index items in a list (for example "mylist[3]") and you can select sub-ranges (for example "mylist[2:4]"). They are dynamic in the sense that you can add and remove items after the list is created.
Tuples are light-weight lists, but differ from lists in that they are immutable. That is, once a tuple has been created, you cannot modify it. You can, of course, modify any (modifiable) objects that the tuple refers to.
Capabilities of lists:
Capabilities of lists and tuples:
To create a list use:
>>> items = [111, 222, 333] >>> items [111, 222, 333]
To add an item to the end of a list, use:
>>> items.append(444) >>> items [111, 222, 333, 444]
To insert an item into a list, use:
>>> items.insert(0, -1) >>> items [-1, 111, 222, 333, 444]
You can also push items onto the right end of a list and pop items off the right end of a list with append and pop.
>>> items.append(555) >>> items [-1, 111, 222, 333, 444, 555] >>> items.pop() 555 >>> items [-1, 111, 222, 333, 444]
And, you can iterate over the items in a list with the for
statement:
>>> for item in items: ... print 'item:', item ... item: -1 item: 111 item: 222 item: 333 item: 444
Associative arrays.
Capabilities:
For help on dictionaries, type:
>>> help dict
at Python's interactive prompt, or:
$ pydoc help
at the command line.
Create a dictionary with:
>>> lookup = {} >>> lookup {}
or:
>>> def fruitfunc(): ... print "I'm a fruit." >>> def vegetablefunc(): ... print "I'm a vegetable." >>> >>> lookup = {'fruit': fruitfunc, 'vegetable': vegetablefunc} >>> lookup {'vegetable': <function vegetablefunc at 0x4028980c>, 'fruit': <function fruitfunc at 0x4028e614>} >>> lookup['fruit']() I'm a fruit. >>> lookup['vegetable']() I'm a vegetable.
or:
>>> lookup = dict((('aa', 11), ('bb', 22), ('cc', 33))) >>> lookup {'aa': 11, 'cc': 33, 'bb': 22} >>>
Test for the existence of a key with:
>>> if lookup.has_key('fruit'): ... print 'contains key "fruit"' ... contains key "fruit" >>>
or:
>>> if 'fruit' in lookup: ... print 'contains key "fruit"' ... contains key "fruit" >>>
Access the value of a key as follows:
>>> print lookup['fruit'] <function fruitfunc at 0x4028e614> >>>
>>> for key in lookup: ... print 'key: %s' % key ... lookup[key]() ... key: vegetable I'm a vegetable. key: fruit I'm a fruit. >>>
And, remember that you can sub-class dictionaries. Here are two versions of the same example. The keyword arguments in the second version require Python 2.3 or later:
# # This example works with Python 2.2. class MyDict_for_python_22(dict): def __init__(self, **kw): for key in kw.keys(): self[key] = kw[key] def show(self): print 'Showing example for Python 2.2 ...' for key in self.keys(): print 'key: %s value: %s' % (key, self[key]) def test_for_python_22(): d = MyDict_for_python_22(one=11, two=22, three=33) d.show() test_for_python_22() # # This example works with Python 2.3. # Keyword support, when subclassing dictionaries, seems to have # been enhanced in Python 2.3. class MyDict(dict): def show(self): print 'Showing example for Python 2.3 ...' for key in self.keys(): print 'key: %s value: %s' % (key, self[key]) def test(): d = MyDict(one=11, two=22, three=33) d.show() test()
Running this example produces:
Showing example for Python 2.2 ... key: one value: 11 key: three value: 33 key: two value: 22 Showing example for Python 2.3 ... key: three value: 33 key: two value: 22 key: one value: 11
A few comments about this example:
The print
statement sends output to stdout
.
Here are a few examples:
print obj print obj1, obj2, obj3 print "My name is %s" % name
Notes:
print
statement inserts a blank between objects.
print
statement automatically appends a newline to
output. To print without a newline, add a comma after the last
object, or use "sys.stdout", for example:
print 'Output with no newline',
which will append a blank, or:
import sys sys.stdout.write("Some output")
print
statement, replace sys.stdout with an instance of a class
that supports the write method. For example:
import sys class Writer: def __init__(self, filename): self.filename = filename def write(self, msg): f = file(self.filename, 'a') f.write(msg) f.close() sys.stdout = Writer('tmp.log') print 'Log message #1' print 'Log message #2' print 'Log message #3'
More information on the print
statement is at
http://www.python.org/doc/current/ref/print.html.
Note: Note to Jython users - Jython does not appear to support the file constructor for files. In the above example, replace file with open.
The import
statement makes a module and its contents
available for use.
Here are several forms of the import statement:
A few comments about import
:
import
statement also evaluates the code in the
imported module.
import
statement offers, see the imp module. Documentation at
http://www.python.org/doc/current/lib/module-imp.html.
Also see the __import__
built-in function. Documentation at
http://www.python.org/doc/current/lib/built-in-funcs.html.
More information on import
at
http://www.python.org/doc/current/ref/import.html.
Use the assert
statement to place error checking statements
in you code. Here is an example:
def test(arg1, arg2): arg1 = float(arg1) arg2 = float(arg2) assert arg2 != 0, 'Bad dividend -- arg1: %f arg2: %f' % (arg1, arg2) ratio = arg1 / arg2 print 'ratio:', ratio
When arg2 is zero, running this code will produce something like the following:
Traceback (most recent call last): File "tmp.py", line 22, in ? main() File "tmp.py", line 18, in main test(args[0], args[1]) File "tmp.py", line 8, in test assert arg2 != 0, 'Bad dividend -- arg1: %f arg2: %f' % (arg1, arg2) AssertionError: Bad dividend -- arg1: 2.000000 arg2: 0.000000
A few comments:
The problem -- Imagine a global variable NAME. If, in a function, the first mention of that variable is "name = NAME", then I'll get the value of the the global variable NAME. But, if, in a function, my first mention of that variable is an assignment to that variable, then I will create a new local variable, and will not refer to the global variable at all. Consider:
NAME = "Peach" def show_global(): name = NAME print '(show_global) name: %s' % name def set_global(): NAME = 'Nectarine' name = NAME print '(set_global) name: %s' % name show_global() set_global() show_global()
Running this code produces:
(show_global) name: Peach (set_global) name: Nectarine (show_global) name: Peach
The set_global modifies a local variable and not the global variable as I might have intended.
The solution -- How can I fix that? Here is how:
NAME = "Peach" def show_global(): name = NAME print '(show_global) name: %s' % name def set_global(): global NAME NAME = 'Nectarine' name = NAME print '(set_global) name: %s' % name show_global() set_global() show_global()
Notice the global
statement in function
set_global. Running this code does modify the global
variable NAME, and produces the following output:
(show_global) name: Peach (set_global) name: Nectarine (show_global) name: Nectarine
Comments:
global
statement. For example:
global NAME1, NAME2, NAME3
The
Here is an example:
A few notes:
if statement enables us to execute code (or not)
depending on a condition.
are described at
http://www.python.org/doc/current/ref/summary.html.
>>> y = 25
>>>
>>> if y > 15:
... print 'y is large'
... else:
... print 'y is small'
...
y is large
switch
statement. Use if-elif
.
Or consider using a dictionary, for example:
def function1(): print "Hi. I'm function1." def function2(): print "Hi. I'm function2." def function3(): print "Hi. I'm function3." mapper = {'one': function1, 'two': function2, 'three': function3} while 1: code = raw_input('Enter "one", "two", "three", or "quit": ') if code == 'quit': break if code not in mapper: continue mapper[code]()
The for
statement enables us to iterate over collections. It
enables us to repeat a set of lines of code once for each item in a
collection. Collections are things like strings (arrays of
characters), lists, tuples, and dictionaries.
Here is an example:
>>> collection = [111,222,333] >>> for item in collection: ... print 'item:', item ... item: 111 item: 222 item: 333
Comments:
>>> aDict = {'cat': 'furry and cute', 'dog': 'friendly and smart'} >>> aDict.keys() ['dog', 'cat'] >>> aDict.values() ['friendly and smart', 'furry and cute'] >>> for key in aDict.keys(): ... print 'A %s is %s.' % (key, aDict[key]) ... A dog is friendly and smart. A cat is furry and cute.
>>> for key in aDict: ... print 'A %s is %s.' % (key, aDict[key]) ... A dog is friendly and smart. A cat is furry and cute.
>>> infile = file('tmp.txt', 'r') >>> for line in infile: ... print line, ... This is line #1 This is line #2 This is line #3 >>> infile.close()
>>> anIter = iter([11,22,33]) >>> for item in anIter: ... print 'item:', item ... item: 11 item: 22 item: 33
yield
(instead of
with return
). Here is an example:
>>> def t(collection): ... icollection = iter(collection) ... for item in icollection: ... yield '||%s||' % item ... >>> for x in t(collection): print x ... ||111|| ||222|| ||333||
while
is another repeating statement. It executes a block of
code until a condition is false.
Here is an example:
>>> reply = 'repeat' >>> while reply == 'repeat': ... print 'Hello' ... reply = raw_input('Enter "repeat" to do it again: ') ... Hello Enter "repeat" to do it again: repeat Hello Enter "repeat" to do it again: bye
Comments:
break
statement to exit from a loop. This
works for both for
and while
. Here is an example that
uses break
in a for
statement:
# for_break.py """Count lines until a line that begins with a double #. """ import sys def countLines(infilename): infile = file(infilename, 'r') count = 0 for line in infile.readlines(): line = line.strip() if line[:2] == '##': break count += 1 return count def usage(): print 'Usage: python python_101_for_break.py <infilename>' sys.exit(-1) def main(): args = sys.argv[1:] if len(args) != 1: usage() count = countLines(args[0]) print 'count:', count if __name__ == '__main__': main()
continue
statement to skip the remainder of the
code block in a for
or while
. A continue
is a
short-circuit which, in effect, branches back to the top of the
for
or while
(or if you prefer, to the end of the
block).
Use a try:except:
block to catch an exception.
Use raise
to raise an exception.
Comments and hints:
except:
. For
example:
>>> try: ... x = y ... except: ... print 'y not defined' ... y not defined
Note, however, that it is usually better to catch specific exceptions.
except:
. To determine what error or exception you want
to catch, generate it and try it. Because Python reports errors
with a walk-back that ends with reporting the exception, you can
learn which exception to catch. For example, suppose I want to
learn which exception is thrown when a Python can't open a file. I
can try the following from the interactive prompt:
>>> myfile = file('amissingfile.py', 'r') Traceback (most recent call last): File "<stdin>", line 1, in ? IOError: [Errno 2] No such file or directory: 'amissingfile.py'
So, now I know that I can do:
>>> try: ... myfile = file('amissingfile.py', 'r') ... except IOError: ... print 'amissingfile.py is missing' ... amissingfile.py is missing
try: #f = open('abcdexyz.txt', 'r') d = {} x = d['name'] except (IOError, KeyError), e: print 'The error is --', e
Note that multiple exceptions to be caught by a single
except:
clause are in parentheses; they
are a tuple.
raise
and catching that object in
the except:
. By doing so, you can pass information up from
the raise
statement to an exception handler. One way of
doing this is to pass an object. A reasonable strategy is to
define a sub-class of a standard exception. For example:
>>> class E(RuntimeError): ... def __init__(self, msg): ... self.msg = msg ... def getMsg(self): ... return self.msg ... >>> >>> try: ... raise E('my test error') ... except E, obj: ... print 'Msg:', obj.getMsg() ... Msg: my test error
try:except:
, but then
find that you do not want to handle the exception at that
location, you can "re-raise" the same exception (with the
same arguments) by using raise
with no arguments. An
example:
class GeneralException(Exception): pass class SimpleException(GeneralException): pass class ComplexException(GeneralException): pass def some_func_that_throws_exceptions(): #raise SimpleException, 'this is a simple error' raise ComplexException, 'this is a complex error' def test(): try: some_func_that_throws_exceptions() except GeneralException, e: if isinstance(e, SimpleException): print e else: raise test()
To read a text file, first create a file object. Here is an example:
inFile = file('messages.log', 'r')
Then use one or more of the file object's methods to process the contents of the file. Here are a few strategies:
>>> inFile = file('tmp.txt', 'r') >>> content = inFile.read() >>> inFile.close() >>> print content aaa bbb ccc ddd eee fff ggg hhh iii >>> words = content.split() >>> print words ['aaa', 'bbb', 'ccc', 'ddd', 'eee', 'fff', 'ggg', 'hhh', 'iii'] >>> for word in words: ... print word ... aaa bbb ccc ddd eee fff ggg hhh iii
Example:
>>> inFile = file('tmp.txt', 'r') >>> for line in inFile: ... print 'Line:', line, ... Line: aaaaa Line: bbbbb Line: ccccc Line: ddddd Line: eeeee >>> inFile.close()
>>> inFile = file('tmp.txt', 'r') >>> lines = inFile.readlines() >>> print lines ['aaaaa\n', 'bbbbb\n', 'ccccc\n', 'ddddd\n', 'eeeee\n'] >>> print lines[2] ccccc >>> inFile.close()
Note: You will need a sufficiently recent version of Python in order to use iterators and generators. I believe that they were introduced in Python 2.2.
Goals for this section:
Definitions:
next
and a __iter__
method
which satisfy these rules: (1) the __iter__
method must
return the iterator; (2) the next
method should return each
of the items to be iterated over and when finished should raise
the StopIteration
exception. The iterator protocol is
described in 2.3.5 Iterator Types.
next
and __iter__
methods as described above and in
2.3.5 Iterator Types.
yield
statement automatically becomes a generator.
A few additional basic points:
yield
statement is a generator
function. When called, it returns an iterator, that is, an object
that provides next
and __iter__
methods.
next
method and a
__iter__
method satisfies the iterator protocol. So,
instances of such a class will be iterators.
for
statement, in a list comprehension, and in a
generator expression. When an iterator is used in an iterator
context, the iterator produces its values.
This section attempts to provide examples that illustrate the generator/iterator pattern.
Why is this important?
Examples - The remainder of this section provides a set of examples.
This function contains a yield
statement. Therefore, when we
call it, it produces an iterator.
def generateItems(seq): for item in seq: yield 'item: %s' % item anIter = generateItems([]) print 'dir(anIter):', dir(anIter) anIter = generateItems([111,222,333]) for x in anIter: print x anIter = generateItems(['aaa', 'bbb', 'ccc']) print anIter.next() print anIter.next() print anIter.next() print anIter.next()
Running this example produces the following output:
dir(anIter): ['__class__', '__delattr__', '__doc__', '__getattribute__', '__hash__', '__init__', '__iter__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__str__', 'gi_frame', 'gi_running', 'next'] item: 111 item: 222 item: 333 item: aaa item: bbb item: ccc Traceback (most recent call last): File "iterator_generator.py", line 14, in ? print anIter.next() StopIteration
Notes and explanation:
for
statement to iterate over the values returned by the generator.
StopIteration
exception. This ability to call the next method enables
us to pass the iterator object around and get values at different
locations in our code.
StopIteration
exception, it should continue to do so.
Another way to say this is that there is no "rewind" operation.
But, you can call the the generator function again to get a
"fresh" iterator.
Each time this method is called, it produces a (new) iterator object. This method is analogous to the iterkeys and itervalues methods in the dictionary built-in object.
# # A class that provides an iterator generator method. # class Node: def __init__(self, name='<noname>', value='<novalue>', children=None): self.name = name self.value = value self.children = children if children is None: self.children = [] else: self.children = children def set_name(self, name): self.name = name def get_name(self): return self.name def set_value(self, value): self.value = value def get_value(self): return self.value def iterchildren(self): for child in self.children: yield child # # Print information on this node and walk over all children and # grandchildren ... def walk(self, level=0): print '%sname: %s value: %s' % ( get_filler(level), self.get_name(), self.get_value(), ) for child in self.iterchildren(): child.walk(level + 1) # # An function that is the equivalent of the walk() method in # class Node. # def walk(node, level=0): print '%sname: %s value: %s' % ( get_filler(level), node.get_name(), node.get_value(), ) for child in node.iterchildren(): walk(child, level + 1) def get_filler(level): return ' ' * level def test(): a7 = Node('gilbert', '777') a6 = Node('fred', '666') a5 = Node('ellie', '555') a4 = Node('daniel', '444') a3 = Node('carl', '333', [a4, a5]) a2 = Node('bill', '222', [a6, a7]) a1 = Node('alice', '111', [a2, a3]) # Use the walk method to walk the entire tree. print 'Using the method:' a1.walk() print '=' * 30 # Use the walk function to walk the entire tree. print 'Using the function:' walk(a1) test()
Running this example produces the following output:
Using the method: name: alice value: 111 name: bill value: 222 name: fred value: 666 name: gilbert value: 777 name: carl value: 333 name: daniel value: 444 name: ellie value: 555 ============================== Using the function: name: alice value: 111 name: bill value: 222 name: fred value: 666 name: gilbert value: 777 name: carl value: 333 name: daniel value: 444 name: ellie value: 555
Notes and explanation:
yield
statement in the method
iterchildren makes it into a generator.
yield
statement returns one item each time it is
reached. The next time the iterator object is "called" it
resumes immediately after the yield
statement.
yield
statements.
for
statement will iterate over all the items
produced by an iterator object.
This class implements the iterator protocol. Therefore, instances of this class are iterators. The presence of the next and __iter__ methods means that this class implements the iterator protocol and makes instances of this class iterators.
Note that when an iterator is "exhausted" it, normally, cannot be reused to iterate over the sequence. However, in this example, we provide a refresh method which enables us to "rewind" and reuse the iterator instance.
# # An iterator class that does *not* use ``yield``. # This iterator produces every other item in a sequence. # class IteratorExample: def __init__(self, seq): self.seq = seq self.idx = 0 def next(self): self.idx += 1 if self.idx >= len(self.seq): raise StopIteration value = self.seq[self.idx] self.idx += 1 return value def __iter__(self): return self def refresh(self): self.idx = 0 def test_iteratorexample(): a = IteratorExample('edcba') for x in a: print x print '----------' a.refresh() for x in a: print x print '=' * 30 a = IteratorExample('abcde') try: print a.next() print a.next() print a.next() print a.next() print a.next() print a.next() except StopIteration, e: print 'stopping', e
Running this example produces the following output:
d b ---------- d b ============================== b d stopping
Notes and explanation:
There may be times when the next method is easier and more straight-forward to implement using yield. If so, then this class might serve as an model. If you do not feel the need to do this, then you should ignore this example.
# # An iterator class that uses ``yield``. # This iterator produces every other item in a sequence. # class YieldIteratorExample: def __init__(self, seq): self.seq = seq self.iterator = self._next() self.next = self.iterator.next def _next(self): flag = 0 for x in self.seq: if flag: flag = 0 yield x else: flag = 1 def __iter__(self): return self.iterator def refresh(self): self.iterator = self._next() self.next = self.iterator.next def test_yielditeratorexample(): a = YieldIteratorExample('edcba') for x in a: print x print '----------' a.refresh() for x in a: print x print '=' * 30 a = YieldIteratorExample('abcde') try: print a.next() print a.next() print a.next() print a.next() print a.next() print a.next() except StopIteration, e: print 'stopping', e test_yielditeratorexample()
Running this example produces the following output:
d b ---------- d b ============================== b d stopping
Notes and explanation:
yield
, calling
it (actually, calling the iterator object it produces) in an
iterator context causes it to be "resumed" immediately after the
yield
statement. This reduces bookkeeping a bit.
yield
statement, and is therefore a generator.
The following code in our constructor (__init__)
completes the set-up of
our class as an iterator class:
self.iterator = self._next() self.next = self.iterator.next
Remember that we need both __iter__ and next methods in order to satisfy the iterator protocol. The __iter__ is already there and the above code in the constructor creates the next method.
A list comprehension looks a bit like an iterator, but it produces a list.
See 5.2.4 List displays for more on list comprehensions.
Here is an example:
In [4]: def f(x): ...: return x * 3 ...: In [5]: list1 = [11, 22, 33] In [6]: list2 = [f(x) for x in list1] In [7]: print list2 [33, 66, 99]
A generator expression looks quite similar to a list comprehension, but is enclosed in parentheses rather than square brackets. Unlike a list comprehension, a generator expression does not produce a list; it produces an iterator object.
For more on generator expressions, see 5.2.5 Generator expressions.
The following example uses a generator expression to produce an iterator.
mylist = range(10) def f(x): return x*3 genexpr = (f(x) for x in mylist) for x in genexpr: print x
Notes and explanation:
(f(x) for x in mylist)
produces an iterator object.
This section describes Python features that you can use to organize and structure your code.
Use def
to define a function. Here is a simple example:
def test(msg, count): for idx in range(count): print '%s %d' % (msg, idx) test('Test #', 4)
Comments:
def
creates a function object.
# Create a tuple: val = (test, 'A label:', 5) # Call the function: val[0](val[1], val[2])
Providing default arguments allows the caller to omit some arguments. Here is an example:
def testDefaultArgs(arg1='default1', arg2='default2'): print 'arg1:', arg1 print 'arg2:', arg2 testDefaultArgs('Explicit value')
The above example prints:
arg1: Explicit value arg2: default2
Here is an example:
def testArgLists_1(*args, **kwargs): print 'args:', args print 'kwargs:', kwargs testArgLists_1('aaa', 'bbb', arg1='ccc', arg2='ddd') def testArgLists_2(arg0, *args, **kwargs): print 'arg0: "%s"' % arg0 print 'args:', args print 'kwargs:', kwargs print '=' * 40 testArgLists_2('a first argument', 'aaa', 'bbb', arg1='ccc', arg2='ddd')
Running this example displays:
args: ('aaa', 'bbb') kwargs: {'arg1': 'ccc', 'arg2': 'ddd'} ======================================== arg0: "a first argument" args: ('aaa', 'bbb') kwargs: {'arg1': 'ccc', 'arg2': 'ddd'}
A little guidance:
Define a basic class as follows:
class Basic: def __init__(self, name): self.name = name def show(self): print 'Basic -- name: %s' % self.name obj1 = Basic('Apricot') obj1.show()
Running the above example produces the following:
Basic -- name: Apricot
Explanation:
def
. The first
argument to a method is the class instance. By convention it is
spelled "self".
__init__
there are other special method
names of the form "__XXX__", which are used to customize classes
and their instances. These are described at
http://www.python.org/doc/current/ref/specialnames.html.
A few more notes on self:
Define a class Special
that inherits from a super-class
Basic
as follows:
class Basic: def __init__(self, name): self.name = name def show(self): print 'Basic -- name: %s' % self.name class Special(Basic): def __init__(self, name, edible): Basic.__init__(self, name) self.upper = name.upper() self.edible = edible def show(self): Basic.show(self) print 'Special -- upper name: %s.' % self.upper, if self.edible: print "It's edible." else: print "It's not edible." def edible(self): return self.edible obj1 = Basic('Apricot') obj1.show() print '=' * 30 obj2 = Special('Peach', 1) obj2.show()
Running this example produces the following:
Basic -- name: Apricot ============================== Basic -- name: Peach Special -- upper name: PEACH. It's edible.
Comments:
A class data member is a member that has only one value for the class and all its instances. Here is an example from the Python FAQ at http://www.python.org/doc/FAQ.html:
class C: count = 0 # number of times C.__init__ called def __init__(self): C.count = C.count + 1 def getcount(self): return C.count # or return self.count c1 = C() print 'Current count:', c1.getcount() c2 = C() print 'Current count:', c2.getcount()
Running this example produces:
Current count: 1 Current count: 2
New-style classes can have static methods and class methods.
A new-style class is a class that inherits directly or indirectly from object or from a built-in type.
Here is an example that shows how to define static methods and class methods:
class Advanced(object): def __init__(self, name): self.name = name def Description(): return 'This is an advanced class.' def ClassDescription(cls): return 'This is advanced class: %s' % repr(cls) Description = staticmethod(Description) ClassDescription = classmethod(ClassDescription) obj1 = Advanced('Nectarine') print obj1.Description() print obj1.ClassDescription() print '=' * 30 print Advanced.Description() print Advanced.ClassDescription()
Running the above produces the following output:
This is an advanced class. This is advanced class: <class __main__.Advanced at 0x401c926c> ============================== This is an advanced class. This is advanced class: <class __main__.Advanced at 0x401c926c>
Notes:
You should also review the relevant standard Python documentation which you can find at Python Library Reference - 2.1 Built-in Functions.
By now, you are likely to be asking: "Why and when should I use class methods and static methods?" Here is a bit of guidance, though
To summarize:
A new-style class can have properties. A property is an attribute of a class that is associated with a getter and a setter function.
Declare the property and its getter and setter functions with property().
Here is an example:
class A(object): count = 0 def __init__(self, name): self.name = name def set_name(self, name): print 'setting name: %s' % name self.name = name def get_name(self): print 'getting name: %s' % self.name return self.name objname = property(get_name, set_name) def test(): a = A('apple') print 'name: %s' % a.objname a.objname = 'banana' print 'name: %s' % a.objname test()
Running the above produces the following output:
getting name: apple name: apple setting name: banana getting name: banana name: banana
Notes:
You can use a module to organize a number of Python definitions in a single file. Here is an example:
# python_101_module_simple.py """ This simple module contains definitions of a class and several functions. """ LABEL = '===== Testing a simple module =====' class Person: """Sample of a simple class definition. """ def __init__(self, name, description): self.name = name self.description = description def show(self): print 'Person -- name: %s description: %s' % (self.name, self.description) def test(msg, count): """A sample of a simple function. """ for idx in range(count): print '%s %d' % (msg, idx) def testDefaultArgs(arg1='default1', arg2='default2'): """A function with default arguments. """ print 'arg1:', arg1 print 'arg2:', arg2 def testArgLists(*args, **kwargs): """ A function which references the argument list and keyword arguments. """ print 'args:', args print 'kwargs:', kwargs def main(): """ A test harness for this module. """ print LABEL person = Person('Herman', 'A cute guy') person.show() print '=' * 30 test('Test #', 4) print '=' * 30 testDefaultArgs('Explicit value') print '=' * 30 testArgLists('aaa', 'bbb', arg1='ccc', arg2='ddd') if __name__ == '__main__': main()
Running the above produces the following output:
===== Testing a simple module ===== Person -- name: Herman description: A cute guy ============================== Test # 0 Test # 1 Test # 2 Test # 3 ============================== arg1: Explicit value arg2: default2 ============================== args: ('aaa', 'bbb') kwargs: {'arg1': 'ccc', 'arg2': 'ddd'}
Comments:
$ pydoc python_101_module_simple
Or this, from the Python interactive prompt:
>>> import python_101_module_simple >>> help(python_101_module_simple)
A package is a way to organize a number of modules together as a unit. Python packages can also contain other packages.
To give us an example to talk about, consider the follow package structure:
package_example/ package_example/__init__.py package_example/module1.py package_example/module2.py package_example/A.py package_example/B.py
And, here are the contents:
# __init__.py # Expose definitions from modules in this package. from module1 import class1 from module2 import class2
# module1.py class class1: def __init__(self): self.description = 'class #1' def show(self): print self.description
# module2.py class class2: def __init__(self): self.description = 'class #2' def show(self): print self.description
# A.py import B
# B.py def function_b(): print 'Hello from function_b'
In order to be used as a Python package (e.g. so that modules can be imported from it) a directory must contain a file whose name is __init__.py. The code in this module is evaluated the first time a module is imported from the package.
In order to import modules from a package, you may either add the
package directory to sys.path
or, if the parent directory is
on sys.path
, use dot-notation to explicitly specify the
path. In our example, you might use: "import
package_example.module1".
A module in a package can import another module from the same package directly without using the path to the package. For example, the module A in our sample package package_example can import module B in the same package with "import B". Module A does not need to use "import package_example.B".
You can find additional information on packages at http://www.python.org/doc/essays/packages.html.
Suggested techniques:
>>> from package_example import * >>> dir() ['__builtins__', '__doc__', '__file__', '__name__', 'atexit', 'class1', 'class2', 'module1', 'module2', 'readline', 'rlcompleter', 'sl', 'sys'] >>> >>> c1 = class1() >>> c2 = class2() >>> c1.show() class #1 >>> c2.show() class #2
A few additional notes:
>>> import zipfile >>> a = zipfile.PyZipFile('mypackage.zip', 'w', zipfile.ZIP_DEFLATED) >>> a.writepy('Examples') >>> a.close()
Then you can import and use this archive by inserting its path in sys.path. In the following example, class_basic_1 is a module within package mypackage:
>>> import sys >>> sys.path.insert(0, '/w2/Txt/Training/mypackage.zip') >>> import class_basic_1 Basic -- name: Apricot >>> obj = class_basic_1.Basic('Wilma') >>> obj.show() Basic -- name: Wilma
Thanks to the implementors of Python for producing an exceptionally usable and enjoyable programming language.
See Also:
This document was generated using the LaTeX2HTML translator.
LaTeX2HTML is Copyright © 1993, 1994, 1995, 1996, 1997, Nikos Drakos, Computer Based Learning Unit, University of Leeds, and Copyright © 1997, 1998, Ross Moore, Mathematics Department, Macquarie University, Sydney.
The application of LaTeX2HTML to the Python documentation has been heavily tailored by Fred L. Drake, Jr. Original navigation icons were contributed by Christopher Petrilli.