Making a Program
After having used it for almost four years now, I've come to find that Python is an extremely capable language, equal in power to C++, Java, et al. If you don't need the "finesse" the major languages provide, I highly recommend learning Python or another dynamic language like Ruby. You'll program faster with fewer errors (like memory management) and can harness the power of a built-in GUI for rapid prototyping of applications. You can also use these languages for quick scripts to speed repetitive tasks. Plus, they are inherently cross-platform so you can easily switch between OSes or find a larger market for your programs. Heck, Python is used extensively by Google, NASA, and many game publishers, so it can't be all that bad.
One of the biggest complaints people have is the forced use of white space and indentation. But if you think about it, that's considered a "good coding practice"; it makes it easier to follow the flow of the program and reduces the chance of errors. Plus, since brackets aren’t required, you don't have to worry about your program not working because you forgot to close a nested if statement. After a few days of using Python, you won't even notice, though I imagine you'll notice how "sloppy" other languages look.
Now, on with the show...
Making Python Do Something
So far I've talked about how Python is structured and how it differs from other languages. Now it's time to make some real programs.
Python programs are comprised of functions, classes, modules, and packages.
In reality, I consider modules and packages to be "programs". It just depends on how many separate files are required to make the program run. Yes, it is possible to have a single, monolithic file that controls the entire program but it's usually better to have different parts in different files. It's actually easier to keep track of what's going on and you can cluster bits of code that have common goals, e.g. have a file that holds library functions, one that handles the GUI, and one that processes data entry.
An important module to know is the Python standard library. The library is a collection of common code blocks that you can call when needed. This means you don't have to "rebuild the wheel" every time you want to do something, such as calculate the tangent of a function. All you have to do is import the portion of the standard library you need, e.g. the math block, and then use it like regular Python code. Knowing what's in the standard library separates the good programmers from the great ones, at least in my book.
That being said, let's make a
simple Python program. This program can be made in IDLE (the standard
Python programming environment that comes with the Python install), a
third-party programming environment (such as SPE, Komodo, Eclipse,
BoaConstructor, etc.), or a simple text editor like Window’s
Notepad, vim, emacs, BBEdit, etc. (More programs can be found in the
Appendix).
def square(x): #define the function; “x” is the argument
return x * x #pass back to
caller the square of a number
for y in range(1, 11): #cycle through a list of numbers
print square(y) #print the square of a number
To run this program, simply
save it with a filename, such as “first_program.py”.
Then, from the command prompt simply type “python
first_program.py”. The results should look like this:
$python first_program.py #the “$” is the command prompt indicator
1
4
9
16
25
36
49
64
81
100
This is about as simple as it gets. First we define the function called square() (the parenthesis indicates that it’s a function rather than a statement) and tell it that the argument called x will be used for processing. Then we actually define what the function will do; in this case, it will multiply “x” times itself to produce a square. By using the keyword return, the square value will be given back to whatever actually called the function (in this case, the print statement).
Next we create a for loop that prints the squared value of each number as it increases from 1 to 11. This should be fairly easy to follow, especially with the comments off to the side. Please realize that most programs you'll see aren't commented this much; quite often, the programs aren't commented at all. I like to think that I have a sufficient amount of documentation in my code (you’ll see later) that it's pretty easy for even new programmers to figure out what's going on.
Let’s look at another
program, this one a little more complex.
def adder(*args) :
sum = args[0] # init to arg1
for next in args[1:] :
sum = sum + next # add items 2..N
return sum
>>> adder(2, 3)
5
>>> adder(4, 5, 56)
65
>>> adder("spam", "eggs")
'spameggs'
>>> adder([1,2,3], [4,5,6])
[1, 2, 3, 4, 5, 6]
This little program (which I found in O’Reilly’s Learning Python) is pretty powerful, as you can see. Essentially, it takes a variable number of arguments and either adds them or concatenates them together. These arguments can be anything: numbers, strings, lists, tuples, etc.
A note about the *args keyword. This is a special feature of Python that allows you to enter undesignated arguments and do things to them (like add them together). The * is like a wildcard; it signifies that a variable number of arguments can be given. A similar argument keyword is **kwargs. This one is related (it takes an unlimited number of arguments) but they are set off by keywords. This way, you can match variables to the arguments based on the keywords. More information can be seen in the Default Keywords section below.
Scope
What? You didn't know snakes got bad breath? (I know, bad joke.) Seriously though, scope describes the area of a program where an identifier (a name for something, like a variable) can access the it's associated value. Scope ties in with namespaces because namespaces pretty much define where an identifier's scope is.
In simple terms, namespaces store information about an identifier and it's value. Python has three namespaces: local, global, and built-in. When an identifier is first accessed, Python looks for it's value locally, i.e. it's surrounding code block. In the example above, “x” is defined within the function square(). Every function is assigned its own local namespace. Functions can't use identifiers defined in other functions; they're simply not seen. If a function tries to call a variable defined in another function, you'll get an error. If a function tried to define a previously defined variable, you'll just get a brand new variable that happens to have the same name but a different value.
However, if an identifier isn't defined locally, Python will check if it's in the global namespace. The global namespace is different from the local one in that global identifiers can be used by other functions. So if you made global variable cars_in_shop = 2, all functions in the program can access that variable and use it as needed. So you can define a variable in one location and have it used in multiple places without having to make it over and over.
The built-in namespace is set aside for Python's built-in functions. (Kinda convenient, huh?) So keywords and standard function calls like range() are already defined when the Python interpreter starts up and you can use them "out of the box".
As you may have figured out,
namespaces are nested:
built-in
|--global
|--local
If an identifier isn't found locally, Python will check the global namespace. If it's not there Python will check the built-in namespace. If it still can't find it, it coughs up and error and dies.
One thing to consider (and I touched on slightly) is that you can hide identifiers as you go down the namespace tree. If you have cars_in_shop = 2 defined globally, you can make a function that has the exact same name with a different value, e.g. cars_in_shop = 15. When the function calls this variable, it will use the value of 15 vs. 2 to calculate the result. This can cause problems if you don't have good variable names since you may forget which variable you're actually using.
Default Arguments
When you create a function, you
can set it up to use default values for it's arguments, just in case
the item calling it doesn't have any arguments. For example:
def perimeter(length = 1, width = 1):
return length * width
If you want to call this particular function, you can supply it with the necessary measurements ( perimeter(15, 25) ) or you can supply one ( perimeter(7) ) or you can just use the defaults ( perimeter() ). Each argument is matched to the passed in values, in order, so if you're going to do this make sure you know which arguments are going to be matched.
You can also use keyword arguments, which match arguments based on a corresponding keyword. This way, you don't have to worry about the order they are given. So for the “perimeter()” example above, you could simply say “perimeter(width = 12)”. This will make the function use 1 for the length and 12 for the width. This is easier than remembering the order of the arguments; however, it also means more typing for you. If you have a lot of functions with these types of arguments, it can become tedious.
Also, once you give a keyword for an argument, you can’t go back to not naming them and try to rely on position to indicate the matchup. For example:
def abstract_function(color = “blue”, size = 30, range = 40, noodle = True)
abstract_function(“red”, noodle = False, 45, range = 50) #not allowed
Trying it call it this way will give you an error. Once you start using keywords, you have to continue for the rest of the argument set.
That's about it for programming with functions. Their pretty simple and the more examples you see, the more they'll make sense. Python is cool since you can mix functions and classes (with methods) in the same module without worrying about errors. This way you aren't constrained to one way of programming; if a short function will work, you don't have to take the time to make a full-blown class with a method to do the same thing.
If you don't want to deal with object-oriented programming, you can stick with functions and have a good time. However, I'll start to cover OOP in later chapters to show you why it's good to know and use. And with Python, it's not as scary as OOP implementation in other languages.