This is the new version of my little introduction to Python. I wrote an old one HERE. Python 3.0 brought some slight changes, which I had to take care of. In the end I also added a small section answering the question "Why to use Python?".


Hello World

Bearbeiten

Lets start with my slighly advanced version of the hello word program

print("Hello World")
 
# Functions
def funny_function(x):
    print ("I am a function called with parameter ", x)
 
funny_function("Horsefly")
 
# conditionals
if 1 == 2:
    print("One and Two are the same")
elif 1 == 1:
    print("One and One are the same")
else:
    print("One and One are different")
 
# the while loop
x = 3
while x > 1:
    print("While", x)
    x -= 1
 
# the for loop
for i in range(1, 3):
    print("For", i)


Versions

Bearbeiten

There are two important groups of versions of Python. 2.x and 3.x, they differ significantly. In this text I am talking about Version 3.x only. Since you are a human being, with free will and the mental power to decide, I leave it to you to choose the version that you can use best to fulfill your personal goals. Someone having read my philosophical ideas will note a lot dark sarcasm in the last sentence, but this is not our topic in this text. Nevertheless you can easily get confused when trying to run code that was written for an other version of Python. It is quite easy to see which version of Python a code in question has been written for.

The old print statement looks like this

print "Hello World"

The new print statement looks like this

print ("Hello World")

So as a rule of thumb. If there are brackets at the print statement, you are in 3.x. Otherwise you are in 2.x.

The next thing I would like to show you are the object oriented features of python. You may skip this section if you are new to programming.

# objects

class Animal:
    def __init__(self):
        """Constructor."""
        self.legs = 0
        self.weight = 0
        # private variable
        self.__answer = 42

    def get_legs(self):
        return self.legs

    def set_legs(self, l):
        self.legs = l

    def get_answer(self):
        return self._answer


class Dog(Animal):
    def __init__(self):
        Animal.__init__(self)
        self.set_legs(4)
        
    def bark(self):
        print("Wow!")
 
a_dog = Dog()
a_dog.bark()
print(a_dog.get_legs())
print(a_dog.weight)
print(a_dog.get_answer())

It is interesting to consider private attributes in Python. _answer is a "private" attribute. Still the privacy is not enforced by the complier or the runtime system. So it is just private by convention. You can get a "better" privacy by writing __answer instead. In this case accessing __answer in the usual way from outside the class will cause a runtime exception, so you have support for privacy in the language. But Python also provides a workaround to overcome this privacy and thus access the private attribute from outside its class. Such mechanisms are also present in other languages. In Python it is common to stick to privacy by convention and thus write _answer instead of __answer. So I uses this level of privacy in the above code. You may play with the double underscore notation to see the other level of privacy.

Of course there are a lot of functions dealing with strings in Python

# Printing a string
print("xyz")
# concatenating strings with the + operator
print("xyz" + "abc")
# multiplying a string
print(3 * "xyz")
# getting the fifth character of a string
print("abcdefg"[4])
# printing the characters 3 to 5 of a string
print("abcdefg"[2:5])
# printing the first 3 characters of a string
print("abcdefg"[:3])
# print the last characters of a string starting from the fourth
print("abcdefg"[3:])
# print the second letter counting from the end of the string
print("abcdefg"[-2])

A very important structure in Python is the list.

# putting together apples and pears
print (["apples", "pears"])
# basically you can to the same things with lists as with stings so
# multiply
print (3 * ["apples", "pears"])
# add
print (["apples", "pears"] + ["spam", "eggs"])
# take the third element
print (["apples", "pears", "spam", "eggs"][2])
# and so on.
# of course you can also do normal stack , list and queue operations
l = ["a", "b", "c"]
print (l)
# appending
l.append("d")
print (l)
# inserting
l.insert(2, "new")
print (l)
# stack poping, pop the element at the end
print (l.pop())
print (l)
# queue poping, pop the element at the beginning
print (l.pop(0))
print (l)
# sorting
l.sort()
print (l)
# remove element by name
l.remove("new")
print (l)
# remove by index
l = [1, 2, 3, 1, 2, 3]
print (l)
del l[2]
print (l)

Containers

Bearbeiten

But of course there are other useful container types too.

# the mapping type: dictionary, an associative array
names = {"dirk": 27, "arthur": 24, "david": 20, "linda": 30}
print (names)
print (names["dirk"])
print (list(names.keys()))
print (list(names.values()))
names.update({"dirk": 28})
print (names)
names["david"] = 21
print (names)
del names["arthur"]
print (names)
print ("dirk" in names)
# the set type
a_list = [1, 2, 3, 4, 1, 2]
print (a_list)
a_set = set(a_list)
print (a_set)
# "element of" relationship
print (1 in a_set)
print (5 in a_set)
a_tuple = set([4, 5])
# set difference
print (a_set - a_tuple)
# set union
print (a_set | a_tuple)
# set intersection
print (a_set & a_tuple)
# set symmetric difference
print (a_set ^ a_tuple)

Here come a short introduction to the way you loop through sequences in Python

names = {"john": 23, "anna": 30, "elis": 26}
for key, value in names.items():
    print ("The key " + key + " has got the value " + str(value))

fruit = ["apple", "banana", "orange"]
for number, item in enumerate(fruit):
    print ("The fruit", item, "is number", number)
    
drinks = ["juice", "water", "lemonade"]
for fruit_item, drink_item in zip(fruit, drinks):
    print (drink_item, fruit_item)
    
for item in reversed(["a", "b", "c", "d"]):
    print (item)

Functional

Bearbeiten

There is a programming paradigm called functional programming. It is not so frequently used, but still its charming in a certain way, and since python offers some support for it, I will briefly show it to you.


from operator import *
#alternative way of defining function
square=lambda x: x*x
print(square(2))
print(square(3))
#list comprehension
l = [1, 2, 3, 4, 5 ]
print ([a * 2 for a in l])
print ([a for a in l if a % 2 == 1])
print ([a * 2 for a in l if  a % 2 == 1])

#the map function (don't mix it up with HashMap or TreeMap)
print (list(map( (lambda x:x+10 ), l)) )

#the filter function
print (list(filter( (lambda x:x % 2 == 0), l ) ) )

More on Functional Programming

Bearbeiten

This section shows some more complicated examples of functional programming, and might be confusing to someone who did not work with functional languages before. I just included it because I am interested in this field. It is not so common to use this style when programming in Python.

# a more complex example
# the following lines show data from a (idealized) physics experiment.
# the first row contains Voltages in [V], the second one electrical currents  in [A].
# both measured at a perfect resistor, obeying Ohms law.
# The task is to calculate the resistance in Ohms.
# so you basically have to calculate (1. / 4. + 2. / 8 + ... + 6. / 24.) / 6.
f="""1., 2., 3., 4., 5., 6.
 4., 8.,12.,16.,20.,24."""

a=[ map ( float, x.split(",") ) for x in f.split("\n") ]
print (sum( [ x[0] / x[1] for x in zip( a[0] , a[1] ) ] ) / 6. )


# foldl

def foldl (func ,value, li):
  if li==[] : return value 
  else: return foldl( func, func(value,li[0]), li[1:]) 

print (foldl (mul, 1, l))       # product
print (foldl (add, 0, l))       # sum
print (foldl (max, l[0], l[1:]))  # max

z=[2,4,8,10]
mean=lambda x,y: x*(y[0]+1)/(y[0]+2)+y[1]/(y[0]+2)
tail=list(enumerate(z[1:]))

print (foldl (mean ,z[0], tail  ) ) # arithmetic mean

Exercise

Bearbeiten

Some Magic

Bearbeiten

The following lines are magic, just store them to the file mathparser.py

import parser
import pprint
import symbol
import token
import types

d = symbol.sym_name
d.update(token.tok_name)

def do(x):
    if type(x) == types.StringType:
        return x
    try:
        l = len(x)
    except:
        l = 1
    if l > 1:
        try:
            h = d[x[0]]
        except:
            h = x[0]
        if h in ["arith_expr"]:
            l = [h]
        else:
            l = []
        for e in x[1:]:
            l += [do(e)]
        return l
    else:
        return x
        
def press(x):
    if type(x) == types.StringType:
        return x
    if len(x) == 1:
        try:
            return press(x[0])
        except:
            return x
    try:
        return [press(a) for a in x]        
    except:
        return x
    return x

def clean(x):
    if type(x) == types.StringType:
        return x
    try:
        return filter(lambda x: x not in ['arith_expr', "(", ")", ""], [clean(a) for a in x])
    except:
        return x
    return x

def consume(x):
    if type(x) == types.StringType:
        return x
    if len(x) > 2:
        return [consume(x[1]), consume(x[0]), consume(x[2:])]
    if len(x) == 2:
        return [consume(x[0]), consume(x[1])]    
    return consume(x[0])


def parse(x):
    p = parser.expr(x).tolist()
    u = press(clean(press(do(p))))
    return press(clean(consume(u)))

Your Task

Bearbeiten

This is the description the task you can do

import mathparser
import types

print mathparser.parse("x * x * x")

# Task 1:
# Write a program that generates something like this:
# (x * (x * x))
# from the given source list

# HINT
# You can check whether something is a string by writing:
# if type(x) == types.StringType:
# an so on.

# Task 2:
# Write a program that calculates the first derivative of the given input list.
# The output format shall be a list of the same kind.


# Task 3:
# Combine 1 and 2 to get the derivative in the usual notation.

Solution

Bearbeiten

This is my solution to the problem

import types
import mathparser

def pri(x):
    if type(x) == types.StringType:
        return x
    if len(x) == 2:
        return x[0] + "(" + pri(x[1]) + ")"
    if x[0] in "+-*/":
        return "(" + pri(x[1]) + " " + x[0] + " " + pri(x[2]) + ")"

def mult(a, b):
    if ((b == "0") or (a == "0")):
        return "0"
    elif a == "1":
        return b
    elif b == "1":
        return a
    else:    
        return ["*", a, b]
        
def add(a, b):
    if a == "0":
        return b
    elif b == "0":
        return a
    else:
        return ["+", a, b]

def derive(x):
    TODO = "I will not calculate this derivative because the guy who programmed me didn't want me to"
    BADMATH = "I will not calculate this derivative because, mathematicins can prove that it won't work all the time"
    if x == "x":
        return "1"
    if type(x) == types.StringType:
        return "0"
    if x[0] == "+":
        return add(derive(x[1]), derive(x[2]))
    elif x[0] == "-":
        return [x[0], derive(x[1]), derive(x[2])]
    elif x[0] in "*/":
        a = mult(derive(x[1]), x[2])
        b = mult(x[1], derive(x[2]))
        if x[0] == "*":
            return add(a, b)
        else:
            return ["/", ["-", a, b], ["*", x[2], x[2]]]
    elif x[0] == "sin":
        return mult(["cos", x[1]], derive(x[1])) 
    elif x[0] == "cos":
        return mult(mult("-1", ["sin", x[1]]), derive(x[1]))  
    elif x[0] in ["ceil", "fabs", "floor", "fmod", "frexp"]:
        raise BADMATH
    elif x[0] in ["modf", "ldexp"]:
        raise TODO
    elif x[0] == "exp":
        return mult(["exp", x[1]], derive(x[1]))
    elif x[0] == "log":
        if len(x) == 2:
            return mult(["/", "1", x[1]], derive(x[1])) 
        else:
            raise TODO
    elif x[0] == "log10":
        return derive(["log", x[1], "10.0"])
    elif x[0] == "pow":
        if not contains_x(x[2]):
            return ["pow", x]
        else:
            raise TODO

print (pri(mathparser.parse("x * x * x")))
print (derive(mathparser.parse("x * x * x")))
print (pri(derive(mathparser.parse("x * x * x"))))

Why to use Python

Bearbeiten

There are many reasons for using python. One is certainly scripting applications, or use of Python as glue to bring together existing solutions to solve your particular problem, here the rich standard library combined with full support for object oriented concepts. An other one thing is in the field of prototyping.

Here I will just give a simple example, since I am not really working in the field. If you are writing a new application and want to play with different implementations it often happens that you have to add a new method to a class. But since you usually use interfaces instead of the classes directly (at least if you are using Java), you either have downcast from the interface to your more specific class, which is bad style. Or you can modify the interface, but than you will have to implement the method all classes implementing the interface, which does not always make sense. In Python you have a weaker type concept. So Python will (to put it in an oversimplified way) always cast automatically to the type you just need.

So you can argue that this is bad style to, well but at least you don't have to take the trouble of declaring all these interfaces. Well if Software engineering is more your way of doing things you can hope that you designed everything so well that you will not have these kinds of problems, but often costumers come up with new requirements while you are implementing your design than you might find yourself in exactly that situation.

I see another application for python in the field training. I think it makes an excellent first language. The list is certainly not exhaustive, but I think it can give you an idea that Python is something useful, and not just something beautiful.

Now I will explain why I think that python is a good first language. I think that the container types of the standard library (set, map, list, etc.) are very important and you should learn about them as early as possible, especially since I spent a significant amount of my time at work for enlarging array boundaries for programs which were designed for a limited length of input files which was later on exceeded. In Java or C++ these concepts can only be understood at a very advanced level.

a = [1, 2, 4, 8, 16, 32]
print(a[3] + a[4])

the result is

24

You can explain this code in few minutes to pupil who just finished primary school, who has never had any experience with programming.

In Java you end up with.

import java.util.LinkedList;

public class ListTest {
    public static void main(String[] args) {
        LinkedList<Integer> list = new LinkedList();
        list.add(1);
        list.add(2);
        list.add(4);
        list.add(8);
        list.add(16);
        list.add(32);
        System.out.println(list.get(3) + list.get(4));
    }
}

the result is

24

This is much harder to explain to a pupil. We got a generic type, or alternatively two casts. We have to explain what an Integer is. We instantiate an object. We call methods of and object. So we have to talk about objects right from the beginning. I think this is quite hard for a beginner. I think in python you can very quickly do your own experiments with programming before having studied the theory. And I think this way you will like programming right from the beginning and you will likely keep doing it your whole live long.

Bibliography

Bearbeiten

I learned Python mostly from the online documentation reading only the parts I just needed (lazy loading).

http://docs.python.org/

There is a quite commonly used book on Python.

http://diveintopython3.org/

I did not read it. It looks at very many aspects of the standard library and the language itself in a quite detailed way. So it is not so well suited for beginners. I think you can start writing python code without having studied a lot of theory. In C++ or Java I needed to read a book in order to get things working, in Python things just worked very intuitively, so I did not really need a lot of reading to get things done.