02 Programming Python
02 Programming Python
1 Programming Python
• Section ??
• Section ??
• Section ??
– Lists
– Strings
– Tuples
– Dictionaries
– Sets
• Section ??
• Section ??
• Section ??
• Section ??
Designed for code readability and teaching purposes. Defines blocks with indenta-
tion:
1
in = open("[Link]","r")
out = open("[Link]", "w")
[Link](in)
[Link]()
[Link]()
or
open("[Link]", "w").writelines(open("[Link]"))
read a file in C:
#include <stdio.h>
int main(int argc, char **argv) {
FILE *in, *out;
int c;
in = fopen("[Link]", "r");
out = fopen("[Link]", "w");
while ((c = fgetc(in)) != EOF) {
fputc(c, out);
}
fclose(out);
fclose(in);
}
Dynamic typing: the type of a variable is set from its content, the way it is used and
the methods which can be applied to it (with restrictions)
Duck Typing: When I see a bird that walks like a duck and swims like a duck and quacks like
a duck, I call that bird a duck. The type of a variable is based on its methods and properties
and not explicitly provided.
An important feature of duck typing is that variables with different properties can still be used
in the same sequence of instructions provided they have the properties and methods needed in
this sequence.
A consequence of this feature is that procedures can be simply used with arguments of differ-
ent types if they support the instructions present in the procedure.
Basic types:
• integers
• floats
• complex
• booleans
• strings
strings are sequences of characters (also, we count from 0!):
In [7]: s="mystring"
print(s[0])
s*2
2
m
Out[7]: 'mystringmystring'
Make decisions
if a:
do something
elif b:
do something else
else:
yet another option
Flow control
for i in range(start,end,step):
do something
if a: break
if b: continue
In [8]: Image(filename="[Link]")
Out[8]:
3
%reset: clear all namespace
%hist: print history
%xdel: delete variables
%who: list objects in enviroment (use in combo with ? to know who is who)
Out[9]: 4
Out[10]: 9
open(filename, mode)
mode is one of: ’r’ (Read), ’w’ (Write), ’a’ (Append). If a file opened for ’w’ does not exist it
will be created.
Common methods for file handles include:
In [11]: f = open('[Link]')
<ipython-input-11-b466559a7089> in <module>()
----> 1 f = open('[Link]')
4
In [12]: f = open('[Link]',"w")
[Link]("Dutch Dillon Billy")
[Link]()
2.2 Exercise
Newton’s method allows to estimate the square root of a number a from an initial estimate x:
x + a/x
y=
2
write a function the implements and uses some convergence criterion.
In [16]: #Solution
def newton(a,x,conv=1e-4,maxit=100):
val = a-x
for i in range(maxit):
y = 0.5 * (x+a/x)
if abs(y-x) <= conv:
break
x = y
return y,i
print(newton(4,3))
newton(81,23)
(2.0000000000262146, 3)
Out[16]: (9.00000000005842, 4)
3 Builtins
In the first lesson, when coding "Hello, World!" we have listed the reserved keywords that the
interpreter uses to define the basics constructs of the language:
5
and, as, assert, break, class, continue, def, del, elif, else, except,
exec, finally, for, from, global, if, import, in, is, lambda, not, or,
pass, print, raise, return, try, while, with, yield
In [17]: finally=10
A complete list of reserved keywords can be printed in the interpreter in this way:
Out[18]: ['False',
'None',
'True',
'and',
'as',
'assert',
'break',
'class',
'continue',
'def',
'del',
'elif',
'else',
'except',
'finally',
'for',
'from',
'global',
'if',
'import',
'in',
'is',
'lambda',
'nonlocal',
'not',
'or',
'pass',
'raise',
6
'return',
'try',
'while',
'with',
'yield']
What about other statements that have been presented such as sum or next?
These are built-in functions that are automatically available without importing any module;
they are not keywords however and can be reassigned with something like:
In [19]: sum([1,2,3])
Out[19]: 6
In [20]: sum="sum"
In [21]: sum([1,2,3])
<ipython-input-21-748a1806f572> in <module>()
----> 1 sum([1,2,3])
In [23]: sum([1,2,3])
Out[23]: 6
Out[24]: ['ArithmeticError',
'AssertionError',
'AttributeError',
'BaseException',
'BlockingIOError',
'BrokenPipeError',
'BufferError',
7
'BytesWarning',
'ChildProcessError',
'ConnectionAbortedError',
'ConnectionError',
'ConnectionRefusedError',
'ConnectionResetError',
'DeprecationWarning',
'EOFError',
'Ellipsis',
'EnvironmentError',
'Exception',
'False',
'FileExistsError',
'FileNotFoundError',
'FloatingPointError',
'FutureWarning',
'GeneratorExit',
'IOError',
'ImportError',
'ImportWarning',
'IndentationError',
'IndexError',
'InterruptedError',
'IsADirectoryError',
'KeyError',
'KeyboardInterrupt',
'LookupError',
'MemoryError',
'NameError',
'None',
'NotADirectoryError',
'NotImplemented',
'NotImplementedError',
'OSError',
'OverflowError',
'PendingDeprecationWarning',
'PermissionError',
'ProcessLookupError',
'RecursionError',
'ReferenceError',
'ResourceWarning',
'RuntimeError',
'RuntimeWarning',
'StopAsyncIteration',
'StopIteration',
'SyntaxError',
'SyntaxWarning',
'SystemError',
8
'SystemExit',
'TabError',
'TimeoutError',
'True',
'TypeError',
'UnboundLocalError',
'UnicodeDecodeError',
'UnicodeEncodeError',
'UnicodeError',
'UnicodeTranslateError',
'UnicodeWarning',
'UserWarning',
'ValueError',
'Warning',
'ZeroDivisionError',
'__IPYTHON__',
'__build_class__',
'__debug__',
'__doc__',
'__import__',
'__loader__',
'__name__',
'__package__',
'__spec__',
'abs',
'all',
'any',
'ascii',
'bin',
'bool',
'bytearray',
'bytes',
'callable',
'chr',
'classmethod',
'compile',
'complex',
'copyright',
'credits',
'delattr',
'dict',
'dir',
'divmod',
'dreload',
'enumerate',
'eval',
'exec',
'filter',
9
'float',
'format',
'frozenset',
'get_ipython',
'getattr',
'globals',
'hasattr',
'hash',
'help',
'hex',
'id',
'input',
'int',
'isinstance',
'issubclass',
'iter',
'len',
'license',
'list',
'locals',
'map',
'max',
'memoryview',
'min',
'next',
'object',
'oct',
'open',
'ord',
'pow',
'print',
'property',
'range',
'repr',
'reversed',
'round',
'set',
'setattr',
'slice',
'sorted',
'staticmethod',
'str',
'sum',
'super',
'tuple',
'type',
'vars',
'zip']
10
we have seen some very useful builtins like:
• range
• abs
• enumerate
• sorted
• sum
two additional builtins that are useful with the following data structures are map and filter
4 Data Structures
In the first class we ad a glimpse of lists. In this section we’ll learn how to deal with lists, strings,
tuples, dictionaries and sets.
4.1 Lists
a.k.a. the workhorse data structure of Python The most general type of data collection objects
(iterables) in Python are lists. Lists are ordered, mutable sequences.
In [25]: empty_list = []
another_empty_list = list()
letters = ["Alpha","Bravo","Charlie","Delta","Echo","Foxtrot"]
You can access members of the list using the index of that item:
In [26]: letters[2]
Out[26]: 'Charlie'
Counting starts from 0 (as in C and derived languages). Thus, letters is a 6 elements list whose
first and last elements are:
In [27]: print(letters[0],letters[5])
Alpha Foxtrot
In [28]: letters[6]
<ipython-input-28-862f6fee39e7> in <module>()
----> 1 letters[6]
11
Counting may start from the end of the list and go backwards:
In [29]: print(letters,"\n",letters[-1],letters[-2])
In [30]: letters[3]="Kilo"
letters
In [31]: letters[3]="Delta"
letters
In [32]: Image(filename="[Link]")
Out[32]:
You can add additional items to the list using the .append() and .insert() methods:
In [33]: [Link]("Hotel")
letters
In [34]: [Link](6,"Golf")
letters
In [35]: a=[0,1.1,2];b=["q","e","r"];print(a+b)
12
The in keyword is used to check if an item is in a list (and other iterables):
Out[36]: True
Out[37]: False
The range command is a convenient way to make sequential lists of numbers, from m to n-1:
2
3
4
5
6
7
The lists created above with range have a step of 1 between elements. You can also give a fixed
step size via a third argument:
the result of range by itself is not a list but it can be used to generate a list (more on this later
on):
In [40]: E=list(evens);E
Out[40]: [0, 2, 4, 6, 8]
In [41]: evens[3]
Out[41]: 6
In [42]: E[3]
Out[42]: 6
You can find out how long a list is using the len() command (remember the help() function and
IPython introspection:
In [43]: len(evens)
13
Out[43]: 5
pop returns the last element of the list and removes it.
In [44]: [Link]()
Out[44]: 'Hotel'
In [45]: letters
Lists and strings have something in common: they can both be treated as sequences. You can
iterate on the letters of a string as you would do with a list:
B
r
a
v
o
In [47]: zulu=list("zulu")
zulu
In [48]: "".join(zulu)
Out[48]: 'zulu'
4.1.1 Slicing
Strings and lists support the slicing operation, which you can also use on any sequence. We
already know that we can use indexing to get any single element of a list:
In [49]: letters[2]
Out[49]: 'Charlie'
If we want the list containing the first two elements of a list, we can do this via
In [50]: letters[2:5]
or simply
14
In [51]: letters[:2]
If we want the last items of the list, we can do this with negative slicing:
In [52]: letters[-2:]
which is somewhat logically consistent with negative indices accessing the last elements of the
list.
Slicing is also supported by strings:
In [53]: mystring="mystring";mystring[2:6:2]
Out[53]: 'sr'
Here we used a step in selecting the interval. The general syntax is:
[start:stop:step]
with defaults:
start = 0
stop = -1
step = 1
i.e.
mylist[:len(mylist)]
means
mylist[0:len(mylist):1]
In [55]: list(numbers[-1::-2])
Out[55]: [10, 8, 6, 4, 2, 0]
The mechanism of slicing and indexing presented above for lists works (with little variation)
with other iterables types in Python and in Numpy
List may also be sorted; find out more with help(sorted) or with introspection:
15
In [56]: sorted(list(numbers[-1::-2]))
In [57]: help(sorted)
A custom key function can be supplied to customise the sort order, and the
reverse flag can be set to request the result in descending order.
Lists within lists Lists can be regarded as eterogeneous data containers. Hence, you can create
access and slice lists of lists:
In [59]: mylist[-1]
In [60]: mylist[-1][-1]
Out[60]: 'Zulu'
In [61]: mylist[-1][-1][-1]
Out[61]: 'u'
In [63]: bases=["A","C","G","T"]
purines=list()
[ [Link](base) for base in bases if base in ["A","G"]]
# list comprehension with filter; notice the append method for lists
purines
16
4.1.3 Exercises
1. Access to the element with value ’Sierra’ from the list
[[1,2,3],[["1st","2nd","3rd"],["Alpha","Sierra","Tango"]],"1.0]
2. Write a script which accepts a string from console and print the characters that have even
indexes. If the following string is given as input to the program:
H1e2l3l4o5w6o7r8l9d
Helloworld
4. Given a list of strings, return a list with the strings in sorted order, except group all the
strings that begin with ’x’ first: [’Alpha’, ’Delta’, ’xray’, ’charlie’] yields [’x-ray’, ’alpha’,
’charlie’, ’delta’].
4.1.4 Hints
2 Use list[::2] to iterate a list with step 2. Do you have enough elements in the list?
3 Slicing.
4 sorted()
In [64]: #Solution #1
mylist=[[1,2,3],[["1st","2nd","3rd"],["Alpha","Sierra","Tango"]],1.0]
mylist[1][1][1]
Out[64]: 'Sierra'
In [65]: # Solution 2
s = input()
s = s[::2]
print(s)
H1e2l3l4o5w6o7r8l9d
Helloworld
In [66]: #Solution 3
def find_palyndrome(mystring):
"""
a docstring here
"""
if len(mystring)==1:
print("are you kidding me?")
return None
S = [Link]()
17
S = [Link](" ","")
L = len(S)
half1 = S[:L//2]
if L%2==0:
half2 = S[-1:L//2-1:-1]
else:
half2 = S[-1:L//2:-1]
if half1 == half2:
return True
else:
return False
find_palyndrome("i topi non avevano nipoti")
Out[66]: True
In [67]: #solution 4
def front_x(words):
x_list = list()
other_list = []
for w in words:
if [Link]('x'):
x_list.append(w)
else:
other_list.append(w)
return sorted(x_list) + sorted(other_list)
front_x(['Alpha', 'Delta', 'xray', 'charlie'])
4.2 Strings
In [68]: #create astring
mystring = "Alpha Bravo"
mystring[10]
Out[68]: 'o'
Out[69]: ['A', 'l', 'p', 'h', 'a', ' ', 'B', 'r', 'a', 'v', 'o']
18
split separates a string into substrings using as a separator a character, by default a whitespace
alternative ways of creating strings:
Out[73]: False
Out[74]: True
In [79]: s="alpha"
s
Out[79]: 'alpha'
In [80]: print(s[0])
s[0] = "A"
19
TypeErrorTraceback (most recent call last)
<ipython-input-80-4f353cc8805c> in <module>()
1 print(s[0])
----> 2 s[0] = "A"
4.3 Tuples
A tuple is a sequence object like a list or a string. It’s constructed by grouping a sequence of objects
together with commas, either without brackets, or with parentheses. At variance with list, tuples
are immutable, they don’t have append, insert or pop methods.
In [81]: t = ("tinker","taylor","soldier","spy")
t
In [82]: t[0]
Out[82]: 'tinker'
In [83]: t[-1]
Out[83]: 'spy'
In [84]: T = tuple()
T = T + t
T
In [85]: T[3]="sailor"
<ipython-input-85-0288282d7354> in <module>()
----> 1 T[3]="sailor"
20
4.3.1 Exercise
Given a list of non-empty tuples, return a list sorted in increasing order by the last element in each
tuple.
yields
4.3.2 Hint
Hint: use a custom key= function to extract the last element form each tuple.
def sort_last(tuples):
return sorted(tuples, key=yield_last)
sort_last( [(1, 7), (1, 3), (3, 4, 5), (2, 2)])
4.4 Dictionaries
A unordered mapping of keys to values. Associate a key with a value. Each key must be unique.
Keys and values may be of any type and may be mixed.
The keys() and values() methods return list generators; list([Link]()) will give you a list.
The items() method returns a a generator of a list of tuples of length 2: (key:value). Why tuples?
In [87]: Image(filename="[Link]")
Out[87]:
21
Out[89]: {'K': 'lysine', 'P': 'proline'}
In [91]: [Link]()[0]
<ipython-input-91-5ae461251ae3> in <module>()
----> 1 [Link]()[0]
In [92]: list([Link]())
In [93]: [Link]()
In [94]: 'K' in a
Out[94]: True
In [95]: 'Q' in a
Out[95]: False
In [96]: 'lysine' in a
Out[96]: False
being mutable, you can eliminate items from dicts, using del
Dictionaries can be used in a function definition to define optional keyword arguments creating
very flexible interfaces:
22
In [98]: import math
def distance(**kwargs):
for key, value in [Link]():
if key is "def":
metric = value
if key is "v1":
v1 = value
if key is "v2":
v2 = value
if len(v1) != len(v2):
return False
dist = .0
if metric is "euclidean":
for i in len(v1):
dist = dist + (v1[i]-v2[i])**2
dist = [Link](dist)
elif metric is "cityblock":
for i in len(v1):
dist = dist + abs(v1[i])+abs(v2[i])
else:
print("I miss this definition")
return None
4.4.1 Exercises
1. Write a program that accepts a sentence and calculate the number of letters and digits:
hello, world! 123
LETTERS 10 DIGITS 3
2. Given a dictionary d and a key k, it is easy to find the corresponding value v = d[k]. This
operation is called a lookup. But what if you have v and you want to find k? You have two
problems: first, there might be more than one key that maps to the value v. Depending on
the application, you might be able to pick one, or you might have to make a list that contains
all of them. Second, there is no simple syntax to do a reverse lookup; you have to search.
Write a function that performs a reverse lookup and test it.
3. Look at the txt file [Link]; it contains several HIV sequences. Write a program to
load each of them in a appropriate container and then for each file calculate the proportion
of each base in each sequence. Before using the actual file it may be wise test your program
with something like that (You may want to write a script and use %run):
Seq1 AAAACCCGGT
Seq2 AGCTACGTATA
Seq3 AGCTACGTATA
23
Out[99]: 'HIV-1.A ATGGGTGCGAGAGCGTCAATATTAAGCGGGGGAAGATTAGATGCATGGGAGAAAATTCGGCTAAGGCCAGGGGGAAAG
In [101]: # Solution 1
s = input()
d={"DIGITS":0, "LETTERS":0}
for c in s:
if [Link]():
d["DIGITS"]+=1
elif [Link]():
d["LETTERS"]+=1
print("LETTERS", d["LETTERS"])
print("DIGITS", d["DIGITS"])
In [102]: #Solution 2
def reverse_lookup(d, v):
for k in d:
if d[k] == v:
return k
# a simple print may make your day
raise ValueError
#what if I have more than one key mapping the same value?
In [103]: #Solution 3
%run [Link] [Link]
24
T 0.21928060768543342
A 0.3668453976764969
C 0.17605004468275245
Composition of sequence HIV-1.D_12 is
G 0.2374673060156931
T 0.22144725370531823
A 0.3632301656495205
C 0.17785527462946818
Composition of sequence HIV-1.D_13 is
G 0.23284401479890202
T 0.22389306599832914
A 0.3694951664876477
C 0.17376775271512113
Composition of sequence HIV-1.D_14 is
G 0.23487179487179488
T 0.22347578347578348
A 0.36752136752136755
C 0.17413105413105412
Composition of sequence HIV-1.A_3 is
G 0.2390728476821192
T 0.22119205298013245
A 0.3612582781456954
C 0.178476821192053
Composition of sequence HIV-1.B_4 is
G 0.24416092190554584
T 0.22255376067496657
A 0.35096203313098057
C 0.18232328428850705
Composition of sequence HIV-1.B_6 is
G 0.24132947976878613
T 0.22154290795909293
A 0.36227212094264116
C 0.17474433081369498
Composition of sequence HIV-1.C_9 is
G 0.2370723064998339
T 0.22190233639685528
A 0.3620861477134315
C 0.1789392093898793
Composition of sequence HIV-1.C_11 is
G 0.24126068138941295
T 0.21962046387748307
A 0.36133614471201864
C 0.17778271002108534
Composition of sequence HIV-1.C_8 is
G 0.24054023886594486
T 0.2202254715928117
A 0.36566581091639694
C 0.17356847862484653
25
Composition of sequence HIV-1.A_0 is
G 0.2342217607015115
T 0.2188761970693435
A 0.3710626514364832
C 0.17364716741663783
Composition of sequence HIV-1.A_1 is
G 0.24452971067095303
T 0.22233744685263923
A 0.3512392409001348
C 0.18189360157627293
Composition of sequence HIV-1.B_7 is
G 0.23647271904007244
T 0.22039846049354767
A 0.36427439438532944
C 0.1785148290695042
4.5 Sets
A set is an unordered, mutable sequence of data with no duplicate elements. It has the form:
In [104]: not_a_set=[0,1+1j,"foo","foo",1+1j]
print(not_a_set)
myset = set(not_a_set)
myset
In [105]: myset[0]
<ipython-input-105-01e3b57caf5b> in <module>()
----> 1 myset[0]
They are mostly used for membership testing and to eliminate duplicate entries. Sets support
mathematical operations like:
26
1. union: The returned set contains the elements of all sets.
2. intersection: The returned set contains the elements common to all sets.
3. difference: The returned set contains the elements of the first set, which are not in the others.
4. symmetric difference: The returned set contains elements, which are present in only one
set.
In [106]: another_set={0,1+1j,"bar"}
In [107]: another_set.union(myset)
In [108]: mytuple=("foo","bar")
mytuple
In [109]: another_set.difference(mytuple)
In [110]: another_set.symmetric_difference(myset)
4.5.1 Exercise
Given a list of words (buzfoo, foobar, barbuz, buzbuz) find the minimum set of lenght=3 prefixes
and suffixes (foo, bar, buz)
In [111]: #Solution
def find_min(words):
prefix = list()
suffix = list()
for w in words:
[Link](w[:3])
[Link](w[-3:])
prefix = set(prefix)
return [Link](suffix)
words = ("foofoo","bazbar","barbaz","foobar","xyzxyz","qwertyu")
find_min(words)
27
4.6 Data structures summary
-- Lists, sets and dictionaries are extensible and mutable.
-- Tuples, on the other hand:
-- Not extensible
{1, 2, 3}
Out[113]: ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']
28
In [115]: mylist.__next__()
Out[115]: 0
In [116]: list(mylist)
Out[116]: [1, 2, 3, 4, 5, 6, 7, 8, 9]
What happened? map returned a iterator object that applies int to every element in mylist,
when invoked with __next__ or list(). Python2 map used to return directly a list:
In [117]: %%python2
a=map(int,list("012345678"))
print a, type(a)
Out[118]: [0, 1, 0, 1, 0, 0, 1, 0, 1, 1]
In [119]: tuple(filter(None,mylist))
Out[119]: (1, 1, 1, 1, 1)
[7, 15, 20, 20, 3, 21, 22, 19, 31, 33, 19, 9, 15, 28, 16, 8, 10, 19, 16, 32]
Out[121]: (7, 20, 20, 3, 21, 22, 19, 19, 9, 28, 16, 19, 16, 32)
The lambda operator allows us to build anonymous functions, which are simply functions that
aren’t defined by a normal def statement with a name. For example, a function that triples the
input is:
29
In [122]: def triplex(x): return 3*x
triplex(3)
Out[122]: 9
Out[123]: 9
what’s the point of this? lambda is particularly useful when you need a simple throw away
function to be used in combination with map or filter:
4.8 Exercise
Write a function filter_long_words() that takes a list of words and an integer n and returns the list
of words that are longer than n
In [125]: #Solution:
words = ["short","loooooong","veeeeeryyyy looooonnnnngggg"]
def flong(tofilt,maxl = 6):
return tuple(filter(lambda x: len(x)>maxl,tofilt))
print(flong(words))
5 Regular expressions
Regular expressions are a powerful string manipulation tool. All modern languages have similar
library packages for regular expressions Use regular expressions to: 1. Search a string (search and
match) 2. Replace parts of a string (sub) 3. Break strings into smaller pieces (split)
The two basic functions are [Link] and [Link].
Search looks for a pattern anywhere in a string.
Match looks for a match staring at the beginning.
Both return None (logical false) if the pattern isn’t found and a “match object” instance if it is.
Different matches may be referred to using groups.
In [126]: import re
pat = "a*b"
SE = [Link](pat,"fooaaabcde")
SE
30
In [127]: MA = [Link](pat,"fooaaabcde")
print(MA)
None
In [128]: [Link](0)
Out[128]: 'aaab'
Out[129]: 'finin'
In [130]: [Link]()
• | Or
• \d Any digit
5.1 Exercises
1. Why in "finin@[Link]" we have groups ’[Link]’ and ’umbc.’ in the regular ex-
pression above?
31
2. A website requires the users to input username and password to register. Write a program
to check the validity of password input by users. Following are the criteria for checking the
password:
Your program should accept a sequence of comma separated passwords and will check them
according to the above criteria. Passwords that match the criteria are to be printed, each separated
by a comma. If the following passwords are given as input to the program:
ABd1234@1,a AF1#,2w3E* ,2We3345
Then, the output of the program should be:
ABd1234@1
In [132]: #Solution
import re
value=list()
pwlist = input("Enter password list: ").split(",")
for p in pwlist:
if len(p)<6 or len(p)>12:
continue
else:
pass
if not [Link]("[a-z]",p):
continue
elif not [Link]("[0-9]",p):
continue
elif not [Link]("[A-Z]",p):
continue
elif not [Link]("[!$#@]",p):
continue
elif [Link]("\s",p):
continue
else:
pass
[Link](p)
value = ",".join(value)
print(value)
32
6 Variable scope
When a variable a is created:
a = ["q","w"]
you associate (bind) "a" name to a memory location holding the tuple (q,w). You can later use
a in another contaniner, such as a dictionary:
In [135]: another_list
In [136]: a_list_of_lists
Out[137]: 'w'
In [138]: print(alist,another_list,a_list_of_lists)
what happened?
33
In [139]: Image(filename="[Link]")
Out[139]:
In [140]: Image(filename="[Link]")
Out[140]:
34
How we can copy alist into another_list?
In [142]: myvar = 3
mystring = "charlie"
mylist = list(mystring)
print(myvar,mystring,mylist)
35
[Link]()
return bvar,bstring,blist
myvar2,mystring2,mylist2 = manipulate_some_variables(myvar,mystring,mylist)
In [144]: print(myvar,mystring,mylist,"\n",myvar2,mystring2,mylist2)
The function works on local copies of variables and myvar and mystring; the third argument
however is affected; why?
In Fortran whenever a subroutine or function is called you can modified it locally because the
information passed between the caller and the callee is a pointer to the variable. In C you pass
copies of variables but you can modify them locally by passing pointers.
In Python the actual behaviour depends on the nature of the variable being passed. For im-
mutable objects what is passed is actually a copy, i.e. the caller is unaware of any local modifica-
tion done by the callee. Mutable objects however are affected by changes in the callee.
In Fortran, you may write something like:
program callts
Implicit real*8(a-h,o-z)
V1 = 1.d0
V2 = 2.d0
Call reverse(V1,V2)
write(*,*) V1, V2
end program callts
Subroutine reverse(var1,var2)
Implicit real*8(a-h,o-z)
tmp = var1
var1 = var2
var2 = tmp
Return
End
in C:
#include "stdio.h"
36
}
In [146]: a = 0
b = ["q","w"]
c = "string"
d = [2,3]
mutate(a,b,c,d)
print(a,b,c,d)
In [147]: help(id)
37
Help on built-in function id in module builtins:
id(obj, /)
Return the identity of an object.
In [149]: a = 0
b = ["q","w"]
c = "string"
d = [2,3]
mutate(a,b,c,d)
print(id(a),id(b),id(c),id(d))
IMMUTABLE objects are "passed by value" while MUTABLE objects are "passed by refer-
ence". Neither definition is strictly true; both types of variable are more properly names associ-
ated to objects created at the moment of their creation. Within the function references to these
objects are passed. But immutable objects names are associated to new objects that are valid only
within the function.
A function that can modify its arguments is called a modifier otherwise is a pure function. Some
programming languages (e.g. Scheme) forbid mutable data and changes in place and are called
functional languages.
The module copy allows to create copies of mutable objects:
38
In [151]: chemicals = [["Caffeine","Theobromine","Theophylline"],["coffee","cacao","guarana"]]
xantines = [Link](chemicals)
chemicals[0].pop()
xantines
The copy method provides a shallow copy, taking references to objects referred to in the original
names while deepcopy allows to make "hard" copies of everything:
7 Namespaces
A namespace is collection of associations of names and objects belonging to a function, class or
module. From the docs:
"Namespaces can be referred to as mappings associating objects and names in a given con-
text: we have multiple independent namespaces in Python, and names can be reused for different
namespaces."
Namespace precedence:
In [154]: Image(filename="[Link]")
Out[154]:
39
2. Enclosing can be its enclosing function, e.g., if a function is wrapped inside another function.
3. Global refers to the uppermost level of the executing script itself, and
4. Built-in are special names that Python reserves for itself.
<namespace>.<object name>
such as:
[Link]
the global statement allows to make outside aware of the creation of arg3
Do you notice anything dangerous?
global has made arg3 visible across the module namespace not just inside outer
using nonlocal on a variable defined above allows to modify it in the enclosing scope:
40
arg3 = "Delta"
def inside(arg1,arg2):
"""
test namespace rules in inner function
"""
nonlocal arg3
arg2 = [Link]()
arg3 = [Link]()
print("local",arg1,arg2,arg3)
inside(arg1,arg2)
print("enclosing",arg1,arg2,arg3)
arg1 = "Alpha"
arg2 = "Bravo"
outside(arg1,arg2)
print("global",arg3)
<ipython-input-157-a2ad88975f9e> in <module>()
18 arg2 = "Bravo"
19 outside(arg1,arg2)
---> 20 print("global",arg3)
8 Recursion
Functions can also call themselves, something that is called recursion. We’re going to experiment
with recursion by computing the factorial function. The factorial is defined for a positive integer
n as
n! = n(n − 1)(n − 2) · · · 1
First, note that we don’t need to write a function at all, since this is a function built into the
standard math library. Let’s use some introspection:
In [159]: factorial(10)
41
Out[159]: 3628800
In [161]: fact(10)
Out[161]: 3628800
8.1 Exercise
1. The formula by Srinivasa Ramanujan (see also Section ??) can be used to estimate π:
√
1 2 2 ∞ (4k!)(1103 + 26390k)
9801 k∑
=
pi =0 (k!)4 (396)4k
using a while loop and the definition of factorial above, implement it with a convergence
criterion based on the value of the last term computed of 1e-15; test against [Link].
2. Write a function able to find the greatest common divisor of positive integers I1 and I2 .
Try different implementations and compare them; start with a non iterative solution. Hint:
[Link]
In [162]: # Solution 1
# credits to [Link]
def estimate_pi():
"""Computes an estimate of pi.
return 1 / total
In [163]: estimate_pi()
Out[163]: 3.141592653589793
42
In [164]: #Solution 2
def gcd1(a, b):
while a-b:
a, b = b, a - b
return a
In [165]: gcd1(80,48)
Out[165]: 16
In [171]: #Solution 3
def gcd2(a, b):
if a == b:
return a, b
else:
return gcd2(max(a-b,b), min(a-b,b))
In [173]: #Solution 4
def gcd3(a, b):
if b == 0:
return a, 0
else:
return gcd3(b,a%b)
Out[174]: (21, 0)
9 Handling errors
9.1 Type of errors
Syntax – wrong grammar, i.e., breaking the rules of how to write the language, e.g. forgetting
punctuation, misspelling a keyword ...
The program will not run at all with syntax errors
Logic - the program runs, but does not produce the expected results. Using an incorrect for-
mula, incorrect sequence of statements, etc.
From the documentation:
Syntax errors, also known as parsing errors, are perhaps the most common kind of complaint
you get while you are still learning Python:
43
The parser repeats the offending line and displays a little ‘arrow’ pointing at the earliest point
in the line where the error was detected. The error is caused by (or at least detected at) the token
preceding the arrow: in the example, the error is detected at the keyword print, since a colon (’:’)
is missing before it. File name and line number are printed so you know where to look in case the
input came from a script.
Even if a statement or expression is syntactically correct, it may cause an error when an at-
tempt is made to execute it. Errors detected during execution are called exceptions and are not
unconditionally fatal Most exceptions are not handled by programs, however, and result in error
messages as shown here:
In [175]: 1/0
<ipython-input-175-05c9758a9c21> in <module>()
----> 1 1/0
In [176]: unassigned_var
<ipython-input-176-8726d26fadd7> in <module>()
----> 1 unassigned_var
Here we have three types ob built-in exceptions; there are more of them:
IOError
ArithmeticError
MemoryError
OSError
IndentationError
UnboundLocalError
The string printed as the exception type is the name of the built-in exception that occurred.
This is true for all built-in exceptions, but need not mandatory. Standard exception names are
built-in identifiers (not reserved keywords):
44
In [177]: ZeroDivisionError=10
ZeroDivisionError
Out[177]: 10
In [178]: %reset
The rest of the line provides detail based on the type of exception and what caused it.
The preceding part of the error message shows the context where the exception happened, in
the form of a stack traceback. In general it contains a stack traceback listing source lines; however,
it will not display lines read from standard input.
Exception is the parent name of any exception type. Error handling is not limited to standard
exception but may be used in any context with the raise keyword:
In [179]: a=input()
#a must be a float
if type(a) is not float:
raise TypeError
10
<ipython-input-179-ebb3c0a57229> in <module>()
2 #a must be a float
3 if type(a) is not float:
----> 4 raise TypeError
TypeError:
You can define custom exceptions by creating subclasses of Exception or simply (but less flex-
ible) by rising built-in ones.
Once you have a defined a custom exception, it is possible to define a different behaviour from
just terminating the program. A simple way to do it is by using the try/except construct:
In [180]: a=(0,1)
try:
a[0]=2
except TypeError:
print("object is immutable")
45
object is immutable
In [181]: a=(0,1)
try:
a[0]=2
except TypeError as e:
print(e)
In [182]: a=[0,1]
try:
a[2]=2
except (TypeError,IndexError) as e:
print("Catching multiple exceptions")
The series of except statements may be completed with a finally statement which includes
instructions that will be executed if an exception is raised in any block:
In [183]: a=[0,1]
b=("q","w")
try:
a[2] = 2
b[2] = "e"
except (TypeError,IndexError):
b = list(b)
[Link](0)
[Link](0)
finally:
a[2] = 2
b[2] = "e"
print(a,b)
9.2 Exercises
Get used to scope rules: what is the output of following snippets? Guess it before executing
var = 'foo'
def ex2():
var = 'bar'
print 'inside the function var is ', var
46
ex2()
print 'outside the function var is ', var
var = 'foo'
def ex3():
global var
var = 'bar'
print 'inside the function var is ', var
ex3()
print 'outside the function var is ', var
Look at the two files "baby names" in the shared folder. They contain the popularity of male
and female names for babies born in 2006 and 2010.
In [184]: %%bash
awk '/Jacob/' 02/[Link]
awk: fatal: cannot open file `02/[Link]' for reading (No such file or directory)
Write a script that accepts a one or more file names as argument and returns the year and a list
of names in alphabetical order with their ranking:
Write a function to load the data for a given year from a binary file
Looking at the file with a text editor shows the structure of relevant records:
You can start from the following template, Try to make use of the argparse module to add
features to the script (e.g. an output file name).
import pickle
import re
def extract_names(filename):
"""
Given a file name for, returns a list starting with the year followed by the name and strings
"""
# you need: year, names and a counter
47
def save_data(namedict):
"""
save a proper data structure
"""
def main():
args = [Link][1:]
if not args:
print('No input data')
quit()
# save data
if __name__ == '__main__':
main()
10 The End!
48