Python Lesson 01 - Basics

Welcome to the first lesson. Thanks to those who attended.

Contents

A Brief History

Python was conceived in the late 80s by Guido van Rossum. He is the Benevolent Dictator for Life, or BDFL. He was given this title by the Python community because he is the primary decision maker in the Python development process, and does a very good job.

The first version, 0.9, was the first public release to the public. It was released in the early 90s. Python 1.0 was released in 1994, and Python 2.0 was released in 2000. Python 3.0 was released this past December. Python 2.3-2.6 are the most commonly used versions in production today.

(History information available, and taken from Wikipedia: http://en.wikipedia.org/wiki/History_of_the_Python_programming_language)

Before the Basics

Python code can be run in an interactive mode. Type python at your bash prompt to get this interactive terminal. It is very useful. You can use the interactive terminal to test code, ideas, and concepts.

An enhanced interactive interpretor is available on some systems, called ipython. The most visible advantage of ipython is that it has built in tab completion enabled by default.

Try both out in your shell. You may or may not have ipython, but if you have Python installed, you will for sure be able to use the regular python interactive interpretor. ipython is not installed on the customer boxes by default. If it isn't available on your workstation, don't worry about it.

This document has been written in such a way that leaving your interactive interpretor open will be helpful in most cases.

If you need help installing Python, Dive Into Python Chapter 1 is for you. At time of writing, the latest version of the 2.x series of Python is 2.6.2. I highly suggest making this version available to yourself, but Python version 2.3-2.6 will work fine for this lesson. Don't worry about Python 3.0. It isn't yet too widely used, and this lesson won't be very helpful if you are using 3.x.

The Basics

The first lesson covers the following:

The idea was to give an overview of the various things that you might see in Python code. A good understanding of these individual aspects of Python will help you put it all together.

Hello World

If you've programmed before, you've likely seen this before:

print "Hello World"

That's it. If you want to run the Python "Hello World" program, here are the ways to do so:

  1. Open a terminal and type python. When you see >>> you can type print "Hello World" and hit enter:

    jefferya@tam:~$ python
    Python 2.6.1 (r261:67515, Dec  7 2008, 08:27:41)
    [GCC 4.3.2] on linux2
    Type "help", "copyright", "credits" or "license" for more information.
    >>> print "Hello World"
    Hello World
    
  2. Open a text editor, and create a file called hello.py:

    print "Hello World"
    

    Close the text editor and type python hello.py.

  3. Create a shell script. Create a file called hello.py:

    #!/usr/bin/python
    print "Hello World"
    

    You'll need to make this file executable by typing chmod a+x hello.py. You can then run it by typing ./hello.py.

    The #!/usr/bin/python tells your shell which interpretor that should be used for this script. Notice that you can follow these steps, and run the script both by typing ./hello.py and by typing python hello.py.

Low-level Data Types

Let's define something easy. How about an integer?

The easiest way to get comfortable with Python code for me was playing in the interactive interpretor. I still use it extensively when I'm learning about a Python language feature, or learning a new API. When you see >>> in my examples, that means that I'm about to type something into the interactive interpretor:

>>> 1
1

I've defined an integer, and the Python interpretor regurgitated the Python representation of the entity that I've provided. Now, let's store that in a variable:

>>> a = 1

Notice that Python doesn't regurgitate the 1 after I assign it. I can see what a variable holds by typing it at the interactive prompt:

>>> a
1

I can also do operations at this prompt, complete with normal math order of operations

>>> 4 / 2
2
>>> 4 * 2
8
>>> 4 + 2
6
>>> 4 - 2
2
>>> 4 ** 2
16
>>> (2+2)**2
16
>>> 10 % 3
1

Now, let's create a string and store it to a variable:

>>> b = "I am a string."

There are a few more ways to define a string:

>>> c = 'use single quotes instead of double quotes'
>>> d = '''use triple single quotes
...
... I can even use line breaks in a triple quote environment, and include
... 'quotations' and /special/ characters of my own.
... '''
>>> e = """
... Triple double quotes are much more commonly seen than triple single
... quotes. Both are identical in function. Triple quotes just look
... better."""

There are a few other low level data types, but we didn't really cover them too much in class. One would be a decimal:

>>> f = 3.14159
>>> f
3.1415899999999999

Notice this decimal is a floating point number, and is represented by Python a little differently than we expected. This is normal of all programming languages that take advantage of the floating point CPU feature.

Higher Level Data Types

The list is a very useful Python data type. It stores an ordered sequence of Python values:

>>> inner = ['mercury', 'venus', 'earth', 'mars']

I can reference each position in the list, and get the element at that position:

>>> inner[0]
'mercury'
>>> inner[2]
'earth'

Lists can store any valid Python entities. This includes integers, strings, decimals, even other lists. Like variables, it can store just about any Python entity.

Here is some stuff you can do with a list:

>>> inner.append('jupiter')
>>> inner
['mercury', 'venus', 'earth', 'mars', 'jupiter']
>>> inner.remove('jupiter')
>>> inner
['mercury', 'venus', 'earth', 'mars']

What would the remove function do if there were two instances of 'jupiter' ? Use your interactive interpretor, and find out.

What if I need to join two lists?

>>> outer = ['jupiter', 'saturn', 'neptune', 'uranus', 'pluto']
>>> inner
['mercury', 'venus', 'earth', 'mars']
>>> outer
['jupiter', 'saturn', 'neptune', 'uranus', 'pluto']
>>> inner.append(outer)

This doesn't work the way you might expect. Try it in your interactive interpretor to see what it did. This is a very common mistake. I still make it.

If I have two lists and I want to join them, there are two ways to do it:

>>> inner
['mercury', 'venus', 'earth', 'mars']
>>> outer
['jupiter', 'saturn', 'neptune', 'uranus', 'pluto']
>>> inner + outer
['mercury', 'venus', 'earth', 'mars', 'jupiter', 'saturn', 'neptune',
'uranus', 'pluto']

I just used a + operator on two lists. The result is a new list. Both my original lists are still in tact. I didn't assign this to a new variable, so the interactive interpretor output the result.

If I want to modify inner in line, I can do this:

>>> inner.extend(outer)
>>> inner
['mercury', 'venus', 'earth', 'mars', 'jupiter', 'saturn', 'neptune',
'uranus', 'pluto']

Tuples are like lists, except they are defined with () instead of [] and they can't be changed. Why are they useful? Because they are faster.


Dictionaries are very useful. As the name implies, you can use them to store and look up values. This is called a hash table in PERL, and a map in c++. This is a key value lookup. Let's assign an empty dictionary to a variable, and then add some key value lookups:

>>> people = {}
>>> people
{}
>>> people['Fred'] = "good at bowling"
>>> people['Barney'] = "short"
>>> people
{'Barney': 'short', 'Fred': 'good at bowling'}

We can also define a dictionary with initial values with the following format:

>>> people = {'Barney': "short", 'Fred': "good at bowling"}
>>> people
{'Barney': 'short', 'Fred': 'good at bowling'}

Dictionaries are unordered. The keys are placed into memory based on what memory is free, so you may see 'Fred' before 'Barney' instead of the way this example is presented. It is incorrect to say that dictionaries are out of order because they have no order in the first place.

Many things can be done with dictionaries. You can add more keys, delete keys, get a list of keys, get a list of values, etc. How can we tell what all we can do with a python data type or object? It is actually quite easy.

Simple Introspection

Introspection in Python is simply a way for Python code to look at other Python code.

So what all can we do with the dictionary that was created in the last example?

Let's look at what methods are available on our people dictionary using the dir function:

>>> dir(people)
['__class__', '__cmp__', '__contains__', '__delattr__', '__delitem__',
'__doc__', '__eq__', '__format__', '__ge__', '__getattribute__',
'__getitem__', '__gt__', '__hash__', '__init__', '__iter__', '__le__',
'__len__', '__lt__', '__ne__', '__new__', '__reduce__', '__reduce_ex__',
'__repr__', '__setattr__', '__setitem__', '__sizeof__', '__str__',
'__subclasshook__', 'clear', 'copy', 'fromkeys', 'get', 'has_key', 'items',
'iteritems', 'iterkeys', 'itervalues', 'keys', 'pop', 'popitem',
'setdefault', 'update', 'values']

What are all those methods that start with __?!?!

They are methods reserved for Python internal use. We can call them directly, but it is usually silly to do so.

One example is the __str__ method. Let's call that method on our people dictionary:

>>> people.__str__()
"{'Barney': 'short', 'Fred': 'good at bowling'}"

This method returned a string representation of our dictionary. If you call print on something, it does the same thing, but sends the result to standard output.

You know how I said it was silly to call these methods directly? It's because there is an easier way:

>>> str(people)
"{'Barney': 'short', 'Fred': 'good at bowling'}"

The other methods may not be super obvious as to what Python may use them for. Fortunately, there is another function, help:

>>> help(people)

You'll have to run it on your own to get the full effect. It prints each method on the object, along with the documentation string, or docstring. We'll talk about that a little later. What does the __len__ method do? What Python function gives this functionality?

Simple Constructs

Let's look at a simple if statement:

>>> if True:
...     print "Truth"
...
Truth

In the interactive interpretor, you can tell that it is waiting for you to end a code block by switching the prompt from '>>>' to '...'.

Notice that unlike other languages, there were no parenthesis around the conditional statement.

Now that the if statement has been introduced, let's look at some boolean values, and how the evaluate:

>>> True
True
>>> False
False
>>> True or False
True
>>> True and False
False
>>> True and not False
True

This should make enough sense just by looking at it. It can get a little trickier though. Most Python data types can evaluate as True or False. An empty string evaluates to False. Any other string evaluates to True. Any number evaluates to True unless it is zero. An empty list evaluates to False. An empty dictionary evaluates to False. The Python null type, None, evaluates to False. When you evaluate another value as a boolean, it will actually return the "winning value" instead of simply True or False:

>>> "one" and "two"
'two'
>>> "one" or "two"
'one'
>>> "" and "two"
''
>>> "" or "two"
'two'
>>> "one" and ""
''
>>> "one" or ""
'one'
>>> not ""
True
>>> "one" and not ""
True
>>> not "" and "two"
'two'

Don't worry, in practice you don't need to fully understand this part as a beginner. Just keep in mind that you can in fact evaluate a string as a conditional, and it will work. The part about the conditional returning something other than simply True or False is very cool so keep it in your mind as you get more comfortable with Python.

This is the and-or trick. Say I have a boolean variable called DEBUG that may or may not be set to True based on a run time option. I can use this to my advantage:

>>> DEBUG and "debug on" or "debug off"

If debug is set to True, 'debug on' will be returned. If it is False, the string 'debug off' is returned instead.


Back to the if/else statement:

>>> if DEBUG:
...     print "debug on"
... else:
...     print "debug off"

Here is a shorthand way to write if/else statements:

>>> if DEBUG: print "debug on"
... else: print "debug off"

Remember our inner planets? Let's print them in a loop.

for loop:

>>> inner
['mercury', 'venus', 'earth', 'mars']
>>> for planet in inner:
...     print planet
...
mercury
venus
earth
mars

Basically, what the for line says is: "for every single thing in the list 'inner', refer to it as 'planet' and run the following code on that thing." We can use any variable we want here. A common variable that gets used in for loops or other code that needs a temporary placeholder variable is simply i. I've seen i used in other languages too.

A good way to do something a certain number of times is to generate a list using the range function:

>>> range(5)
[0, 1, 2, 3, 4]
>>> for i in range(5):
...     print i
...
0
1
2
3
4

This makes for much cleaner code than assigning a variable, and incrementing from within the loop, though you can do that if you really want to. Let's try with a while loop:

>>> i = 0
>>> while i < 5:
...     print i
...     i = i+1
...
0
1
2
3
4

Code blocks in Python are designated by white space. Many other languages use curly brackets to designate a block of code.

For any Python code that requires a block to follow, you'll need to keep a consistent indentation for the duration of the code block. The generally accepted and preferred code block indentation is four spaces. If you are not consistent, Python will throw an IndentationError. You can nest code blocks too:

for i in range(20):
    if i % 3:
        print i, "is divisible by three"
    else:
        print i, "is not divisible by three"

This for loop includes an if statement inside it, as well as an else statement.

Let's try getting that IndentationError:

>>> if True:
...     print "four spaces"
...      print "five spaces"
  File "<stdin>", line 3
    print "five"
    ^
IndentationError: unexpected indent

Functions

Let's write a simple "Hello World" function. I suggest doing this part in a .py file, and running the file as you make changes. All functions in this section are in example07.py.

A simple function:

def hello_world():
    """
    Prints a simple greeting

    Usage:

    >>> hello_world()
    Hello World
    """
    print "Hello World"

This function is complete with a docstring. You can call help on this function, and the contents of that docstring show up as documentation for this function. The "Usage" section shows an example of what you'd see if you ran this function from the interactive interpretor. Python has a test suite that looks for this type of usage example in docstrings, and tries it out. If there is a discrepancy, the test fails. Writing tests and documentation for larger projects is super important. Don't worry so much about it at this point, but its good to be aware of doctests anyway because they are useful without running the test suite.

Moving forward...

Let's write another function that does something different:

def hello_mars():
    """Prints another simple greeting

    Usage:

    >>> hello_mars()
    Hello Mars
    """
    print "Hello Mars"

We now have two functions that do two similar, but still different things. One of the nice things about programming is that we can reduce the amount of duplicated code if we design our functions right. Let's do that by writing one function that can do what both of these do already:

def hello_planet(planet):
    """Instead of creating lots of functions, let's abstract the task a bit."""
    print "Hello", planet

This function takes exactly one argument: planet. This is called an ordered argument. This function is set up to take one and only one, but you can have more ordered arguments. Since greetings may vary from planet to planet, Let's make another function that takes two ordered arguments:

def greet_planet(greeting, planet):
    """
    Let's abstract even more.
    """

    print greeting, planet

The argument that comes first is the greeting. The second argument is the planet. I can call this function now:

>>> greet_planet("Hello", "World")
Hello World

The first argument gets put into a local variable called greeting and the second argument gets put into one called planet. What if I have no idea how many ordered arguments I may get passed to this function? Here is the construct that puts each ordered argument into a tuple:

def greet_everyone(*args):
    """
    This greeting can handle any number of arguments. Try uncommenting the
    second line to see what all that stuff does. It contains two things we
    haven't talked about yet.

    Note the '*' before args.
    """
    print "Hello", args
    #print "Hello", ", ".join([str(u) for u in args])+"."

And this is what this function looks like if I call it:

>>> greet_everyone('Mercury', 'Venus', 'Earth')
Hello ('Mercury', 'Venus', 'Earth')

Another way of calling the greet_everyone function is to use a list as a pre-built set of arguments:

>>> inner
['mercury', 'venus', 'earth']
>>> greet_everyone(*inner)
Hello ('mercury', 'venus', 'earth')

Note the * before inner when I pass inner as an argument. If I don't use the asterisk, I can still pass a list as an argument, but it is still only one argument.

Another type of arguments are named arguments. This is in contrast to the ordered arguments. Here are the hello_planet and greet_planet functions from before, but changed to use named arguments instead of positional:

def hello_planet_named(planet="World"):
    print "Hello", planet

def greet_planet_named(greeting="Hello", planet="World"):
    print greeting, planet

Here are some examples of using these functions. Try to figure out why each call works the way it does.:

>>> hello_planet_named(planet="Earth")
Hello Earth
>>> hello_planet_named()
Hello World
>>> greet_planet_named(greeting="Hi", planet="Mars")
Hi Mars
>>> greet_planet_named(planet="Mars", greeting="Hi")
Hi Mars
>>> greet_planet_named(planet="Mars")
Hello Mars
>>> greet_planet_named()
Hello World

What if I don't know the number nor the names of the named arguments I'll get in a function? There is a similar construct to the *args. Usually programmers choose to name it **kwargs. The two stars indicate that this entity is to be a dictionary that represents all named arguments with names as keys, and values as values. Here is an example function that can do that:

def greet_everyone_named(**kwargs):
    for key in kwargs.keys():
        print "Hello " + key + ",", "you are very", kwargs[key] + '.'

Let's try it out:

>>> greet_everyone_named(Fred="good at bowling", Barney="short")
Hello Barney, you are very short.
Hello Fred, you are very good at bowling.

We can even pass in a pre-built dictionary:

>>> people
{'Barney': 'short', 'Fred': 'good at bowling'}
>>> greet_everyone_named(**people)
Hello Fred, you are very good at bowling.
Hello Barney, you are very short.

Are functions limited to either ordered arguments or named? No. You can use both in one function. The only thing you have to remember is that ordered functions always come FIRST. Both in the definition and calling of a function:

def greet_alien(name, race, planet='Mars', greeting='Hello'):
    print greeting, name+", you are a", race, "from the planet", planet+"."

Let's try it out:

>>> greet_alien("Jeff", "Human")
Hello Jeff, you are a Human from the planet Mars.
>>> greet_alien("Jeff", "Human", planet="Earth")
Hello Jeff, you are a Human from the planet Earth.
>>> greet_alien("Jeff", "Human", greeting="Hola", planet="Earth")
Hola Jeff, you are a Human from the planet Earth.

That's basically all the basics there are for functions.

Object Oriented Programming

If you aren't familiar with object oriented programming and inheritance, that's fine. You don't need to fully understand all its intricacies to be an effective Python programmer, but you will need a basic understanding of some object oriented principles.

A class is like the design for something. A car manufacturer will create a complete set of Blueprints for a new vehicle before that vehicle is rolling around on the street. A class in programming is like the Blueprints for something that is useful. You can't use a class without creating an instance of that class first. An instance is like rolling a brand new car off the assembly line.

A car can do things, and it can have things done to it. You can get into a car, start it, and drive it down the street. Another class example might be a desk lamp. It also gets designed, and assembled in a factory, and then has uses. You can put a light bulb in it, plug it in, and turn it on.

A software example of object orientation is a video game. The programmer designs the bad guy. The bad guy can shoot the player, take damage, switch weapons, etc. Each instance of this baddie is another enemy of the same type. The programmers didn't have to write the same code 15 times over to get a group of 15 identical bad guys. The programmer simply created one bad guy class, and it gets instantiated 15 times over in the level that requires 15 of these baddies.

The reason I'm introducing object oriented programming is because in Python, everything is an object. The reason I'm including this in the "Basics" lesson of Python is because you'll see Python class definitions, as they are quite common.

Python Classes

If you're new to object oriented programming, don't fret. Just think of classes as a way to hold functions and variables related to each other. Classes are much more powerful than that, but it's a good starting point. The point of this section is just to point out the constructs needed to construct a Python class:

class SimpleClass(object):
    """
    A very simple Python class.
    It doesn't do much.
    """
    world = ""
    def __init__(self, planet="Earth"):
        self.world = planet
    def hello_world(self):
        print "Hello", world

This function has a local variable called world. It is defined as a blank string. Notice that these functions look pretty much like the functions from before, minus the ordered variable self. When this function gets called, the instance of the class that it is a part of gets passed as the first argument, and self is used to refer to that instance.

Also notice that there is a function called __init__. This function gets called first thing after the object is created.

Note

A note on constructors

For those who are familiar with other languages might think that this is the constructor. It actually isn't technically the constructor, as it is called after the object is already instantiated in memory. It's the closest thing to a constructor that we'll get though.

This is only a basic introduction to classes, but make sure that you understand the code here before moving on.

Modules and Packages

Now that we know how to write statements, functions, calls to functions, and classes, we need a way to organize our code on disk. One can put all of these Python constructs into a .py file. This .py file, and all the code it contains is a Python module. A module is a good way to store related classes and functions. Say I have a Python module stored in a file called MyModule.py:

class MT(object):
    """This class does nothing"""
    def do_nothing():
        print "I did nothing"

do_nothing_better():
    print "I did nothing better"

If that file is in my current directory, I can import it into a python interactive interpretor:

>>> import MyModule
>>> instance = MT()
>>> instance.do_nothing()
I did nothing
>>> MyModule.do_nothing_better()
I did nothing better

If you have some code that isn't a function or class definition, it is executed the first time the module is imported. Say I have a file called YourModule.py:

print "I am your module"
def emptyfunction(): pass

It would look like this when I import it:

>>> import YourModule
I am your module
>>> import YourModule

What if we have a complicated project? One that would become completely unmanageable if left in a single .py file? Enter Python packages. A Python package is a way to store and access multiple Python source files, and keep them in the same namespace.

The most basic part of the Python package is the directory that all the .py files will live in. This is just an ordinary directory, plus one extra requirement. It must contain a file called __init__.py. This file can be blank. If you have code that you want executed when the package is imported, you can put it there. If there is no __init__.py file present, then Python will pass over this directory and regard it as just a normal directory instead of a Python package. Here is the directory structure for a Package called OurModules:

.
..
__init__.py
MyModule.py
YourModule.py

Beyond the Basics

You should have at least a conceptual understanding of many of the most common Python elements. There is still much more coming. Next lesson we'll introduce a few more concepts, and try to tie all these things together to make Python really work for us.

Homework

Write a function that takes a few arguments, constructs, and returns a simple e-mail message in a string. Using the function may look something like this:

>>> body = """
This is my test message for my Python Homework.

Thanks,
My Name Here
"""
>>> print test_messages(sender="atest@example.com", to="btest@example.com", \
                        subject="My Python Homework", message_body=body)
From: atest@example.com
To: btest@example.com
Subject: My Python Homework

This is my test message for my Python Homework.

Thanks,
My Name Here

We'll work this function into next week's homework that will let us actually send this e-mail message. I have a similar utility that I use to quickly test customer e-mail accounts.

Contact

If you have any questions, please post them to the mailing list on the Google Group.

I'm also happy to answer questions in person. This document will also be updated to reflect questions and concerns that come up both in person and on the mailing list.

Note

License and Legal

This document is Copyright (c) Jeff Anderson. It is not freely distributable. It is intended to be distributed amongst employees of Bluehost for the purpose of learning the Python language. Any copying or distribution beyond this is not permitted. These terms may be modified at any time by the author.

This notice applies only to the content. The HTML code generated by docutils is in the public domain. The syntax highlighting Javascript is google-code-prettify.