Unix Power ToolsUnix Power ToolsSearch this book

42.3. Python Basics

If you've written code in a procedural or functional language before, many parts of Python will seem familiar. Here's a quick overview of the flavor of the language. There is a lot of both reference and tutorial information available on the web (start at http://www.python.org) as well as in books like O'Reilly's Programming Python. In fact, much of the information in this chapter was gleaned or paraphrased from the official Python reference documentation.

42.3.1. Indentation

The number one complaint of Python detractors is almost always its use of indentation as a significant part of its syntax. Most languages use begin/end tags or curly braces ({}) to mark blocks of code and have line termination punctuation (many use the semicolon (;) as a line termination marker). In Python, indentation is used to define blocks of code, and lines are terminated with a return. The actual amount of indentation within a block is arbitrary, but it must be consistent:

if a:
    statement1
    statement2    # Consistent indentation
else:
    statement3
      statement4  # Inconsistent indentation (error)

Python assumes eight-space tab characters. If you have your editor set to four-space tabs, for example, this can bite you if there are mixed spaces and tabs. Either use eight-space tabs, or stick to spaces.

Long statements can span multiple lines by using the backslash (\) to continue the line:

>>> a = math.cos( 3 * ( x - n ) ) + \
...     math.sin( 3 * ( y - n ) )

Lines that are already grouped within triple-quotes, parentheses (...), brackets [...], or braces {...} can span multiple lines without needing to use the backslash.

Python's indentation requirements take a little getting used to, but they guarantee a certain level of readability, and editors like vim and emacs can keep track of the details for you trivially. (vim has a syntax configuration for editing Python, and emacs and xemacs both have a python-mode specifically for dealing with Python.)

42.3.2. Functions

Both procedural and functional languages organize programs by dividing them into smaller units called functions. Python's approach to functions is inspired by functional languages like Lisp and Scheme, where anonymous functions (lambdas) and operations like eval, apply, map, and reduce are fundamentals of the language.

Functions are defined with the def statement. To define an add function that adds together two arguments and returns the result:

>>> def add(a, b):
...     return a + b

This defines a function and attaches it to the name add in the current namespace; anything with access to this namespace can call this function by simply passing arguments to it:

>>> print add(3, 5)
8

Function arguments can be defined with default values, and variable-length argument lists and keyword arguments are also supported.

Procedural programming languages like Perl and C generally leave functions at that. Functional languages like Lisp, Scheme, and Python take functions to the next level; functions are first-class objects and can be directly manipulated and stored.

Anonymous functions, which are not automatically attached to the current namespace, are created with the lambda statement:

>>> add = lambda a, b: a + b

Lambdas are very useful for traditional functional programming tricks such as using map( ). map( ) takes its first argument (which should be a function or lambda) and runs it over and over, passing each element of the list to the function in turn, generating a new list of the results:

>>> def timesThree(a):
...     return 3 * a
>>> def sum(x, y):
...     return x + y

>>> ints = [1, 2, 3, 4, 5]
>>> multiples = map(timesThree, ints)
>>> print multiples
[3, 6, 9, 12, 15]
>>> print reduce(sum, multiples)
45

If you use functions like map( ) and its cousins apply( ), reduce( ), and filter( ) a lot, your code can get pretty messy before long. Using a lambda allows you to use these functions without having to define a named function with def; instead you can just put the lambda right into the function call as an argument:

>>> ints = [1, 2, 3, 4, 5]
>>> multiples = map(lambda a: 3 * a, ints)
>>> print multiples
[3, 6, 9, 12, 15]
>>> print reduce(lambda x, y: x + y, multiples)
45

Lambdas are limited to a single expression, though that expression may be complex. Multiple statements and nonexpression statements like print and while can't be used in a lambda.

42.3.3. Everything's an Object

Everything in Python is an object. Each object has an identity , a type, and a value. For example, a = 42 creates an object of type integer with the value 42. You can think of the identity of an object as its address in memory; in this case, we've given the name a to that identity. Python's built-in types include fundamental building blocks such as numbers, strings, lists, dictionaries, and files, as well as structuring types like functions, modules, lambdas, and metaclasses. (Yes, a function is an object; it's just an object that implements the "function call" operator.)

Python allows the creation of new types of objects via the class statement. User-defined classes can have class variables and methods, which are shared across all instances of that class. In Python, methods are just functions that happen to be associated with a class (and generally take an instance of that class as the first argument). Instances can also have their own instance variables, specific to each instance.

Instances are created by calling the class object as if it were a function, which creates a new object and calls the _ _init_ _( ) method of the class (if one is defined):

class Account:
    "A simple example class"
    kind = "Checking"
    def _ _init_ _(self, accountHolder, startingBalance):
        self.accountHolder = accountHolder;
        self.balance = startingBalance;

>>> account = Account("Deb", 86753.09)

This creates a new Account object and sets the accountHolder instance variable to Deb and the balance instance variable to $86,753.09. Now, in order to be able to do anything with our Account, we need to define methods to allow manipulation of the balance:

class Account:
    ...
    def deposit(self, depositAmount):
        "Deposit money"
        self.balance = self.balance + depositAmount
    def withdraw(self, withdrawalAmount):
        "Withdraw money"
        self.balance = self.balance - withdrawalAmount
    def inquireBalance(self):
        "Balance inquiry"
        return self.balance

>>> account.deposit(1504.36)
>>> account.withdraw(40.00)
>>> print "Account balance is now $%.2f" % account.inquireBalance( )
Account balance is now $88217.45

42.3.4. Modules and Packages

Modules and packages allow you to organize your code more effectively. Generally, software for Python is also distributed as a module or a package. A module groups a set of functions and classes; a package is a collection of modules and subpackages.

Any Python source file is a module, if you load it using the import statement. Importing a module creates an isolated namespace for the symbols within that file and attaches that namespace to the name of the module. It also executes the code within that module, defining variables, functions, and classes. For example, we might put our Account class in a file account.py, and then, in another file:

import account

checking = account.Account("Deb", 86753.09)

Note that we can't refer to Account directly; we have to refer to it through its imported name, account.Account. If, for convenience, we'd like to access the Account class directly, we can tell Python to import the class into our current namespace as well:

from account import Account

checking = Account("Deb", 86753.09)

Modules are compiled into bytecodes the first time they are imported, allowing them to run faster and be more compact.

Given that a Python module is just a file, it will probably come as no surprise that a Python package is simply a directory with modules in it. To tag a directory as a package rather than just any directory, create a file called _ _init_ _.py (the same name as the method to initialize an object) within that directory. Code within _ _init_ _.py will get run whenever any part of its package is imported. Subpackages are, of course, just subdirectories with their own _ _init_ _.py files.

42.3.5. I/O and Formatting

Dealing with input and output in Python is fairly straightforward; files are objects, and there is a set of methods for dealing with file objects that will be familiar to anyone who's ever done any Unix I/O. Files are opened with open( ), closed with close( ), and read with methods such as read( ) and readline( ).

Unix standard input, standard output and standard error are represented by file objects in the sys module: sys.stdin , sys.stdout, and sys.stderr, respectively.

The print statement prints its arguments to standard output. print can print any object by printing its string representation. Nicely formatted strings are generated using the string formatting (%) operator. % works a lot like C's sprintf( ) routine; you provide a string with special keywords in it and the objects to format and you get back a formatted string:

>>> print "Account balance is now $%.2f" % account.inquireBalance( )
Account balance is now $86753.09
>>> print "Error:  %s(%s)." % (error, error.number)
Error:  File not found(2)

% takes a string and a list of arguments. (If there's only one argument, it can be any object instead of a list.) Any place that you might want to use a string, you can use the string formatting operator. For example:

>>> obj.name = "MyObject: %s" % name
>>> url = urlopen("%s://%s:%d/%s" % (protocol, host, port, path))

42.3.6. wxPython

Python has a couple of ways to build graphical user interfaces. The first was to use Tk, the GUI toolkit from Tcl. More recently, a Python interface to the wxWindows toolkit has been developed and has become very popular.

Extensive information about wxPython is available at http://wxpython.org including documentation and the wxPython distribution itself.

-- DJPH



Library Navigation Links

Copyright © 2003 O'Reilly & Associates. All rights reserved.