1. Intro

1.1. The problem with learning Python

Learning Python is terrible. All tutorials start with the amazement that you can have variables (WOW!) to which you can assign values(Hurray!!). And, although I forced myself to start a number of those courses, I just cannot spend hours going through that kind of basics anymore.

Most courses will stop at some point stop, inviting you to do your own coding to learn further. And that is mostly the point that it gets interesting.

So, none of the tutorials work and all stop where it gets interesting.

Furthermore, Python has a number of inconsistencies and bizarre concepts that make the language harder to learn. Did I just say language? I meant languages, because the changes between version 2 and 3 make it often impossible to exchange programs between them.

As a tutorial exercise, I'll be rewriting my TCL/Tk application for image administration in Python.

1.2. Quick language overview

1.2.1. Basic concepts

Python is an Object language. So most of the code will be in classes or will be calling classes.

Python uses an indent to create blocks, in stead of { }, like in C/C++, Perl, go, java, PHP, Scala etcetera or do/done or the likes. Python is very sensitive to spacing. A block is ended with an empty line.

Comments are marked with #, which is normal for a scripting language.

Python has all the normal flow controls, while, for if-then-else. The syntax is, that an indented block is started with a colon, for example:
for item in iterable_collection:
    # do something

Associative arrays (hashes in Perl) are called dictionaries and behave more or less that same as Perl's hashes:
plaatjes = {
    'molen' = 'mooi',
    'straat' = 'lelijk',
    'cavia' = 'lief',
}
for key, value in plaatjes.iteritems():
    print key, value
molen mooi
straat lelijk
cavia lief

1.2.2. Let's have an argument

Python allows two types of arguments:
  • positional parameters
  • named parameters (called keyword parameters in Python)

Positional parameters are what every language uses. Keyword parameters in general get an initial value and they are optional. As an example:

 

def hello (greet='hi',dest='all the people'):
    print greet, " to ", dest
hello()
hello(dest='you')

 

If you do not know (or care) how many positional parameters and/or keyword parameters you get, you can use the c-style pointers:

 

def print_args(*args, **kwargs):
    print 'Positional:', args
    print 'Keyword:   ', kwargs
    for key in kwargs.keys():
        print "Key=",key,"   Value=",kwargs[key]
        if key == 'foo' :
            print "JA HOOR"
print_args(1, 2, foo='bar', stuff='meep')

Obviously, it's nothing like c's pointers, but it's easier to remember like that.

1.2.3. Lists and references

A special place in hell should be reserved for the one who invented references in Python. Consider the following:
a = [1, 2, 3]
b = a
a = []
print(a)
print(b)
a = [1, 2, 3]
b = a
del a[:]
print(a)
print(b)
a = [1, 2, 3]
b = a[:]
del a[:]
print(a)
print(b)

Which gives as output:
[]
[1, 2, 3]
[]
[]
[]
[1, 2, 3]

Obviously.

This can only be explained by the fact that a = [1, 2, 3] assigns a reference to the list [1, 2, 3] to the variable a and the line b = a assigns the value of a to b. That means that now, a and b both have a reference to the same [1, 2, 3] So when we do a = [] a will be a reference to an empty list and b will still have a reference to the original list. However, if I start doing operations on a list with del a[:] it affects the list and not the reference to the list. So that means that b (which is a reference to the same list) will now also point to the empty list.

Finally, b = a[:] forces a copy of a. So, because it is a copy, emptying a will not empty b.

Pythons garbage collector for orphans seems effective enough, so you don't have to worry about lists that are unrefferencable.

1.2.4. Tuples

Tuples are lists that you cannot change. Because they are static, they are faster. And they use different parentheses. That is all there is to know about them.

Many Python zealots will start talking about mutable and immutable objects. They will also point to semantics, for example:
import time
time.localtime()
(2008, 2, 5, 11, 55, 34, 1, 36, 0)

where, if you delete the days, the minutes become hours. So this is why you have time in tuples instead of lists.

1.2.5. Variable scoping

Because Python does not allow you to scope variables explicitly (PEP 20: Explicit is better than implicit), Python uses the following rules:
  • If a variable is declared global it is assumed to be part of the global namespace.
  • If a variable is declared nonlocal it is part of the parent namespace.
  • If you assign a value to a variable, it is assumed to be part of the local namespace, from the beginning of that context.
  • If you do not assign anything to a variable, it assumed implicitly to be part of the parent namespace
  • Mutating an object (for example deleting parts of a list) is not considered as an assignment

The real fun starts when there are multiple nested namespaces...

1.3. Input Output

In the previous sections, al number of print statements have been used.

Reading stdin is a bit more difficult. If you want to read a number, you can use:
value=input('prompt')

However, if you need a string as input, you must use: