# Python Individualtraining (5 Tage, beginnend 28.10.2019)¶

Der Kurs nahm eine Woche in Anspruch, da hat so einiges Platz. Hier die gesammelten Notizen inklusive Code; für schnell erklärte Sachen gibts ein Jupyter Notebook (Download).

## Exercises¶

### Slide 51, “Exercises: Basics”¶

Write a program that takes a single digit as commandline parameter. Print the English word for that digit.

#!/usr/bin/python3

# Exercises: Basics (~51)

# Write a program that takes a single digit as commandline
# parameter. Print the English word for that digit.

import sys

translation = {
0: 'zero',
1: 'one',
2: 'two',
3: 'three',
4: 'four',
5: 'five',
6: 'six',
7: 'seven',
8: 'eight',
9: 'nine',
}

digit = int(sys.argv[1])
if 0 <= digit <= 9:
print(translation[digit])
else:
print('nix')


### Slide 58, “Exercises: While Loop”¶

Write a program that takes an integer commandline parameter and checks whether that number is prime!

#!/usr/bin/python3

# Exercises: While Loop (~58)

# Write a program that takes an integer commandline parameter and
# checks whether that number is prime!

# Exercises: Lists, Loops, Functions (~94)

# Modify the prime number detection program from one of the previous
# exercises: make the prime number detection a function, and call the
# function instead. The function (is prime() is a likely name) takes a
# number, and returns a boolean value as appropriate.

import sys

def is_prime(candidate):
if candidate < 2:
return False

divisor = 2
while divisor <= candidate//2:
if candidate % divisor == 0:
return False
divisor += 1
else:
return True

candidate = int(sys.argv[1])

print(is_prime(candidate))


### Slide 94, “Exercises: Lists, Loops, Functions”¶

Write a function uniq() that takes a sequence as input. It returns a list with duplicate elements removed, and where the contained elements appear in the same order that is present in the input sequence. The input sequence remains unmodified.

#!/usr/bin/python3

# Exercises: Lists, Loops, Functions (~94)

# Write a function uniq() that takes a sequence as input. It returns a
# list with duplicate elements removed, and where the contained
# elements appear in the same order that is present in the input
# sequence. The input sequence remains unmodified.

# Deviations from the requirement:

# 1. implement uniq() as a generator. use yield to produce items.

# 2. demonstrate how to use uniq() as a filter, connecting nodes
#    together using "pipes" as in the pseudo-filter expression:

#    random | uniq | print

import random

def uniq(l):
'''filter that iterates over the input sequence and produces an item
only if that was not yet seen in the input sequence.

'''

have = set()
for i in l:
if i not in have:
yield i

def randomnumbers(howmany):
"produces'howmany' random numbers."
for _ in range(howmany):
yield random.randrange(10)

for i in uniq(randomnumbers(100)):
print(i)


### Slide 121, “Exercises: Strings”¶

Write a program that receives any number of arguments and prints them out right justified at column 20.

#!/usr/bin/python3

# Exercises: Strings (~121)

# Write a program that receives any number of arguments and
# prints them out right justified at column 20.

import sys

for s in sys.argv[1:]:
while len(s) >= 20:
print(s[:20])
s = s[20:]
print(s.rjust(20))



## Miscellaneous¶

### Famous Generator Introduction¶

Producing an infinite sequence (Fibonacci, what else)

#!/usr/bin/python3

# Generators, yield. implementing an infinite sequence (fibonacci is a
# cool example) which would not be so easy if we had only functions
# (these can only return once).

import time

def fibonacci():
prev = 1
cur = 1

yield prev
yield cur

while True:
next = prev + cur
yield next
prev = cur
cur = next

for fibonum in fibonacci():
print(fibonum)


### eval(): Convert a String into a Python Data Structure¶

During the uniq exercise, people tend to want to pass a Python list from the commandline, naively.

Question: how can I take an argument from the commandline (say, sys.argv[1]) and interpret that as a list?

The following program does that. Call it like so,

$./eval-argv.py '[1, 2, 3, 4]'  (‘$’ is the shell prompt, the quotes are necessary to prevent the shell from splitting arguments at the spaces)

#!/usr/bin/python3

import sys

input_list_string = sys.argv[1]
input_list = eval(input_list_string)
print(input_list)


Here’s a little snippet that demonstrates this. See the docs for more.

#!/usr/bin/python3

# question: from C++ I know that I can overload (arithmetic) operators
# for types/classes that I define. how is this done in Python?

class Integer:
def __init__(self, n):
self.__n = n

@property
def n(self):
return self.__n

def __lt__(self, rhs):
return self.__n < rhs.__n

def __le__(self, rhs):
return not self > rhs

def __eq__(self, rhs):
return self.__n == rhs.__n

self.__n += n
return self

'add: +, called on self, the right hand "a" side in "a+b"'
new_number = self.__n + n
return Integer(new_number)

'radd: +, called on the right hand side if the lhs does not support it'
new_number = n + self.__n
return Integer(new_number)

x = Integer(1)
y = Integer(2)

print('1<2', x < y)
print('2<1', y < x)
print('1>2', x > y)
print('1==1', x == x)
print('1!=1', x != x)
print('1<=2', x <= y)
print('1<=1', x <= x)

x += 1
print(x.n)

z = x + 1
print(z.n)

z = 1 + x
print(z.n)


### Getters and Setters¶

Called “Properties” in Python; see below for a snippet. See the docs for more.

#!/usr/bin/python3

# question: in C# we have getters and setters. how is this done in
# Python?

# answer: use the property *decorator*

class MakesNoSense:
def __init__(self, number):
self.__number = number

@property
def number(self):
return self.__number

@number.setter
def number(self, n):
self.__number = n

num = MakesNoSense(42)
print(num.number)
num.number = 666
print(num.number)


### More on Listcomprehensions and Generator Expressions¶

#!/usr/bin/python3

input_numbers = [1,2,3,4]

def squares(numbers):
'''return a list containing the squares of the numnbers from the input
sequence

'''

list_of_squares = []
for i in numbers:
list_of_squares.append(i**2)
return list_of_squares

print('dumb function: squares({})'.format(input_numbers))
for i in squares(input_numbers):
print(i)

# for such simple things as square numbers, use a list
# comprehension. this makes the code shorter - you omit a function
# definition.
print('list compehension: [n**2 for n in {}]'.format(input_numbers))
for i in [n**2 for n in input_numbers]:
print(i)

# list comprehensions still allocate memory to hold the list. with
# minimal effort, you can save that allocation by transforming the
# list comprehension into a generator expression.
print('generator expression: (n**2 for n in {})'.format(input_numbers))
for i in (n**2 for n in input_numbers):
print(i)


### More on Local and Global Scope and Global Variables¶

#!/usr/bin/python3

# Functions: Local and Global Variables (~92)

def local_assignment():

'''assign to l in local scope. this creates a local variable
l. (variables are generally creates at first assignment.)

'''

l = 7

'''accesses a variable g that has never been assigned to in local
scope. this goes out into the enclosing (global) scope and looks
it up there.

'''

'''assign to g in local scope. this does *not* assign to the global
variable g, but creates a local variable g.

'''

g = 42

def explicit_global_assignment():
global g

print('explicit_global_assignment: before assignment g =', g)
g = 42
print('explicit_global_assignment: after assignment g =', g)

# first assignment to g in global scope creates g in global scope.
g = 666

local_assignment()

print('global g =', g)

explicit_global_assignment()
print('global g =', g)


### Closures: Between Local and Global¶

#!/usr/bin/python3

# closure: at the time of function creation (execution of the 'def
# statement), all referenced names are captured to form an
# intermediate scope, the 'closure'

def create_function(parameter):
loc = 42

# at this point, we have two variables in local scope - 'loc' and
# 'parameter'.
print('create_function: loc={}, parameter={}'.format(loc, parameter))

# with this in place, create a function object by executing the
# def statement. note how the function is not executed, but only
# created/compiled.
def inner_function():
# reference variables loc and parameter. these are defined
# neither in local nor in global scope. but they are found in
# the enclosing scope - the locals of create_function(), which
# forms an intermediate scope, the 'closure', whic his added
# to the lookup chain of inner_function().
print('parameter {}, loc {}'.format(parameter, loc))

return inner_function

f_one = create_function('one')
f_one()
f_two = create_function('two')
f_two()


## Project¶

We had two days left, in addition to the usual three days which are sufficient to learn the basics. A group project was launched, with the somewhat real-life topic “talking to switches and doing all kinds of stuff with that information”.

This gave us the opportunity to discover a couple of areas more closely.

• Object oriented programming (a switch has interfaces, and both have properties)

• Storing all that in databases

• Exception handling

• Commandline interfaces

• Unit testing