# Introduction to Python

This tutorial is prepared by ACM Student Chapter of King Abdullah University of Science and Technology (KAUST).
Parts of this tutorial re-use Scientific Python lectures by Robert Johansson linsensed under Creative Commons Attribution 3.0.

Prerequisites: No prerequisites.

## What is Python?¶

Python is a general-purpose, high-level programming language.

### The main features:¶

• Clarity and simplicity. The language is human-readable, quick and easy to learn, minimalisitc.
• Expressiveness. Achieve the same with fewer lines of code.
In [1]:
import this

The Zen of Python, by Tim Peters

Beautiful is better than ugly.
Explicit is better than implicit.
Simple is better than complex.
Complex is better than complicated.
Flat is better than nested.
Sparse is better than dense.
Special cases aren't special enough to break the rules.
Although practicality beats purity.
Errors should never pass silently.
Unless explicitly silenced.
In the face of ambiguity, refuse the temptation to guess.
There should be one-- and preferably only one --obvious way to do it.
Although that way may not be obvious at first unless you're Dutch.
Now is better than never.
Although never is often better than *right* now.
If the implementation is hard to explain, it's a bad idea.
If the implementation is easy to explain, it may be a good idea.
Namespaces are one honking great idea -- let's do more of those!


### Quick technical details:¶

• Dynamically typed. No need to define the type of variables, function arguments or return types.
• Automatic memory management. No need to explicitly allocate memory. Python will take care of this.
• Interpreted. The code is not compiled, but interpreted and executed on the fly by the Python interpreter.

• Ease of programming.
• Minimal time on developing, debuggin, and maintain the projects.
• Powerful and well designed language:
• Modular, object-oriented, supports functional-style programming.
• Documentation tightly integrated with the code.
• Has a large, powerful, and well designed standard library, and numerous addiotional packages that can be installed literally in a few clicks.

• Slowness compared to C/C++ or Fortran (but there are ways to speed it up!).

## Why Python?¶

• A Large community of users makes it easy to find help and documentation.

• An extensive ecosystem of scientific libraries and environments

• Great performance due to close integration with time-tested and highly optimized codes written in C and Fortran: BLAS, ATLAS BLAS, LAPACK, ARCPACK, ...

• Good support for

• Parallel processing with processes and threads
• Interprocess communication (MPI)
• GPU computing (OpenCL and CUDA)
• Readily available and suitable for use on high-performance computing clusters.

• No license costs, no unnecessary use of research budget.

## Python program files¶

• Python code is usually stored in text files with the file ending ".py":

  myprogram.py
• Every line in a Python program file is assumed to be a Python statement, or part thereof.

• The only exception is comment lines, which start with the character # (optionally preceded by an arbitrary number of white-space characters, i.e., tabs or spaces). Comment lines are usually ignored by the Python interpreter.
• To run our Python program from the command line we use:

  $python myprogram.py • On UNIX systems it is common to define the path to the interpreter on the first line of the program (note that this is a comment line as far as the Python interpreter is concerned):  #!/usr/bin/env python  If we do, and if we additionally set the file script to be executable, we can run the program like this: $ myprogram.py

#### Example:¶

In [2]:
ls scripts/hello-world*.py

scripts/hello-world-broken.py     scripts/hello-world-in-arabic.py  scripts/hello-world.py

In [3]:
cat scripts/hello-world.py

#!/usr/bin/env python

print "Hello world!"

In [4]:
!python scripts/hello-world.py

Hello world!

In [5]:
cat scripts/hello-world-broken.py

#!/usr/bin/env python

print "Hello world!"
print "مرحبا"

In [6]:
!python scripts/hello-world-broken.py

  File "scripts/hello-world-broken.py", line 4
SyntaxError: Non-ASCII character '\xd9' in file scripts/hello-world-broken.py on line 4, but no encoding declared; see http://www.python.org/peps/pep-0263.html for details


### Character encoding¶

The standard character encoding is ASCII, but we can use any other encoding, for example UTF-8. To specify that UTF-8 is used we include the special line

#-*- coding: UTF-8 -*-



at the top of the file.

In [7]:
cat scripts/hello-world-in-arabic.py

#!/usr/bin/env python
#-*- coding: utf-8 -*-

print "مرحبا"

In [8]:
!python scripts/hello-world-in-arabic.py

مرحبا

In [9]:
# IPython supports utf-8 by default
print "مرحبا"

مرحبا


## IPython notebooks¶

This file - an IPython notebook - does not follow the standard pattern with Python code in a text file. Instead, an IPython notebook is stored as a file in the JSON format. The advantage is that we can mix formatted text, Python code and code output. It requires the IPython notebook server to run it though, and therefore isn't a stand-alone Python program as described above. Other than that, there is no difference between the Python code that goes into a program file or an IPython notebook.

#### Main features of the web application: /from IPython docs/¶

• In-browser editing for code, with automatic syntax highlighting, indentation, and tab completion/introspection.
• The ability to execute code from the browser, with the results of computations attached to the code which generated them.
• Displaying the result of computation using rich media representations, such as HTML, LaTeX, PNG, SVG, etc. For example, publication-quality figures rendered by the matplotlib library, can be included inline.
• In-browser editing for rich text using the Markdown markup language, which can provide commentary for the code, is not limited to plain text.
• The ability to easily include mathematical notation within markdown cells using LaTeX, and rendered natively by MathJax.

First, let's see some useful shortcuts for IPython notebook:

• To run a cell click on it and hit shift+enter.
• To create a new cell below: ctrl+m+b
• To create a new cell above: ctr+m+a
• To delete a cell: ctr+m+d
• Undo a cell deletion: ctr+m+z
• Markdown cell to write text: ctrl+m+m
• Code cell: ctrl+m+y
• View all shortcuts: ctrl+m+h

IPython has a number of so-called magic commands. The following are just a few examples.

In [10]:
%%timeit
x = range(10000)
sum(x)

1000 loops, best of 3: 238 µs per loop

In [11]:
%run scripts/hello-world.py

Hello world!


## Modules¶

Most of the functionality in Python is provided by modules. The Python Standard Library is a large collection of modules that provides cross-platform implementations of common facilities such as access to the operating system, file I/O, string management, network communication, and much more.

### References¶

To use a module in a Python program it first has to be imported. A module can be imported using the import statement. For example, to import the module math, which contains many standard mathematical functions, we can do:

In [12]:
import math


This includes the whole module and makes it available for use later in the program. For example, we can do:

In [13]:
import math

x = math.cos(2 * math.pi)

print x

1.0


Alternatively, we can chose to import all symbols (functions and variables) in a module to the current namespace (so that we don't need to use the prefix "math." every time we use something from the math module:

In [14]:
from math import *

x = cos(2 * pi)

print x

1.0


This pattern can be very convenient, but in large programs that include many modules it is often a good idea to keep the symbols from each module in their own namespaces, by using the import math pattern. This would elminate potentially confusing problems with name space collisions.

As a third alternative, we can chose to import only a few selected symbols from a module by explicitly listing which ones we want to import instead of using the wildcard character *:

In [15]:
from math import cos, pi

x = cos(2 * pi)

print x

1.0


It is also possible to rename the function or the imported module

In [16]:
from math import cos as cos1
import math as ma

x = cos1(2 * ma.pi)

print x

1.0


### Looking at what a module contains, and its documentation¶

Once a module is imported, we can list the symbols it provides using the dir function:

In [17]:
import math

print dir(math)

['__doc__', '__file__', '__name__', '__package__', 'acos', 'acosh', 'asin', 'asinh', 'atan', 'atan2', 'atanh', 'ceil', 'copysign', 'cos', 'cosh', 'degrees', 'e', 'erf', 'erfc', 'exp', 'expm1', 'fabs', 'factorial', 'floor', 'fmod', 'frexp', 'fsum', 'gamma', 'hypot', 'isinf', 'isnan', 'ldexp', 'lgamma', 'log', 'log10', 'log1p', 'modf', 'pi', 'pow', 'radians', 'sin', 'sinh', 'sqrt', 'tan', 'tanh', 'trunc']


And using the function help we can get a description of each function (almost .. not all functions have docstrings, as they are technically called, but the vast majority of functions are documented this way).

In [18]:
help(math.log)

Help on built-in function log in module math:

log(...)
log(x[, base])

Return the logarithm of x to the given base.
If the base not specified, returns the natural logarithm (base e) of x.


In [19]:
math.log?

In [20]:
log(10)

Out[20]:
2.302585092994046

Some very useful modules form the Python standard library are os, sys, math, shutil, re, subprocess, multiprocessing, threading.

A complete lists of standard modules for Python 2 and Python 3 are available at http://docs.python.org/2/library/ and http://docs.python.org/3/library/, respectively.

### Exercise 1¶

The os module contains a function named getcwd. Find out what this functions do and print its output

##### Solution¶
In [21]:
# %load solutions/getting_help.py


# Language Synatax¶

## Variables and types¶

### Symbol names¶

Variable names in Python can contain alphanumerical characters a-z, A-Z, 0-9 and some special characters such as _. Normal variable names must start with a letter.

In addition, there are a number of Python keywords that cannot be used as variable names. These keywords are:

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



Note: Be aware of the keyword lambda, which could easily be a natural variable name in a scientific program. But being a keyword, it cannot be used as a variable name.

### Assignment¶

The assignment operator in Python is =. Python is a dynamically typed language, so we do not need to specify the type of a variable when we create one.

Assigning a value to a new variable creates the variable:

In [22]:
# variable assignments
x = 1.0
my_variable = 12.2


Although not explicitly specified, a variable do have a type associated with it. The type is derived form the value it was assigned.

In [23]:
type(x)

Out[23]:
float

If we assign a new value to a variable, its type can change.

In [24]:
x = 1

In [25]:
type(x)

Out[25]:
int

If we try to use a variable that has not yet been defined we get an NameError:

In [26]:
print(y)

---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
<ipython-input-26-36b2093251cd> in <module>()
----> 1 print(y)

NameError: name 'y' is not defined

### Fundamental types¶

In [27]:
# integers
x = 1
type(x)

Out[27]:
int
In [28]:
# float
x = 1.0
type(x)

Out[28]:
float
In [29]:
# boolean
b1 = True
b2 = False

type(b1)

Out[29]:
bool
In [30]:
# complex numbers: note the use of j to specify the imaginary part
x = 1.0 - 1.0j
type(x)

Out[30]:
complex
In [31]:
print(x)

(1-1j)

In [32]:
print(x.real, x.imag)

(1.0, -1.0)


### Type utility functions¶

The module types contains a number of type name definitions that can be used to test if variables are of certain types:

In [33]:
import types

# print all types defined in the types module
print(dir(types))

['BooleanType', 'BufferType', 'BuiltinFunctionType', 'BuiltinMethodType', 'ClassType', 'CodeType', 'ComplexType', 'DictProxyType', 'DictType', 'DictionaryType', 'EllipsisType', 'FileType', 'FloatType', 'FrameType', 'FunctionType', 'GeneratorType', 'GetSetDescriptorType', 'InstanceType', 'IntType', 'LambdaType', 'ListType', 'LongType', 'MemberDescriptorType', 'MethodType', 'ModuleType', 'NoneType', 'NotImplementedType', 'ObjectType', 'SliceType', 'StringType', 'StringTypes', 'TracebackType', 'TupleType', 'TypeType', 'UnboundMethodType', 'UnicodeType', 'XRangeType', '__builtins__', '__doc__', '__file__', '__name__', '__package__']

In [34]:
x = 1.0

# check if the variable x is a float
type(x) is float

Out[34]:
True
In [35]:
# check if the variable x is an int
type(x) is int

Out[35]:
False

We can also use the isinstance method for testing types of variables:

In [36]:
isinstance(x, float)

Out[36]:
True

### Type casting¶

In [37]:
x = 1.5

print(x, type(x))

(1.5, <type 'float'>)

In [38]:
x = int(x)

print(x, type(x))

(1, <type 'int'>)

In [39]:
z = complex(x)

print(z, type(z))

((1+0j), <type 'complex'>)

In [40]:
x = float(z)

---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-40-e719cc7b3e96> in <module>()
----> 1 x = float(z)

TypeError: can't convert complex to float

## Operators and comparisons¶

Most operators and comparisons in Python work as one would expect:

• Arithmetic operators +, -, *, /, // (integer division), '**' power
In [41]:
1 + 2, 1 - 2, 1 * 2, 1 / 2

Out[41]:
(3, -1, 2, 0)
In [42]:
1.0 + 2.0, 1.0 - 2.0, 1.0 * 2.0, 1.0 / 2.0

Out[42]:
(3.0, -1.0, 2.0, 0.5)
In [43]:
# Integer division of float numbers
3.0 // 2.0

Out[43]:
1.0
In [44]:
# Note! The power operators in python isn't ^, but **
2 ** 2

Out[44]:
4
• The boolean operators are spelled out as words and, not, or.
In [45]:
True and False

Out[45]:
False
In [46]:
not False

Out[46]:
True
In [47]:
True or False

Out[47]:
True
• Comparison operators >, <, >= (greater or equal), <= (less or equal), == equality, != inequality, is identical.
In [48]:
2 > 1, 2 < 1

Out[48]:
(True, False)
In [49]:
2 > 2, 2 < 2

Out[49]:
(False, False)
In [50]:
2 >= 2, 2 <= 2

Out[50]:
(True, True)
In [51]:
# equality
[1,2] == [1,2]

Out[51]:
True
In [52]:
# inequality
1 != 1

Out[52]:
False
In [53]:
# objects identical?
l1 = [1,2]
l2 = l1
l1 is l2

Out[53]:
True

### Exercise 2¶

Use Python to evaluate the following expression, for the given variables' values, to get the correct results and print the output

(5 * (a > b) + 2 * (a < b*4) ) / a * c

Note: you will need to use some variables casting

In [54]:
a = 15
b = 5
c = 2.2

# expression evaluation here
val = ???

print(val)

  File "<ipython-input-54-a01ce9f34eb5>", line 6
val = ???
^
SyntaxError: invalid syntax

##### Solution¶
In [55]:
# %load solutions/operators.py

In [56]:
a = 15
b = 5
c = 2.2

# expression evaluation here
val = (float(5*(a>b)) + float(2*(a<(b*4))))/float(a) * c

print(val)

1.02666666667


## Compound types: String, List, and Dict¶

### String¶

Strings are the variable type that is used for storing text messages.

In [57]:
s = "Hello world"
type(s)

Out[57]:
str
In [58]:
# length of the string: the number of characters
len(s)

Out[58]:
11
In [59]:
# replace a substring in a string with somethign else
s2 = s.replace("world", "test")
print(s2)

Hello test


We can index a character in a string using []:

In [60]:
s[0]

Out[60]:
'H'

Heads up MATLAB users: Indexing start at 0!

We can extract a part of a string using the syntax [start:stop], which extracts characters between index start and stop.

NOTE: the start index is included, the stop is excluded.

In [61]:
s[0:5]

Out[61]:
'Hello'

If we omit either (or both) of start or stop from [start:stop], the default is the beginning and the end of the string, respectively:

In [62]:
s[:5]

Out[62]:
'Hello'
In [63]:
s[6:]

Out[63]:
'world'
In [64]:
s[:]

Out[64]:
'Hello world'

Negative indexing from the end of the string:

In [65]:
s[:-2]

Out[65]:
'Hello wor'
In [66]:
s[-1], s[-2]

Out[66]:
('d', 'l')

We can also define the step size using the syntax [start:end:step] (the default value for step is 1, as we saw above):

In [67]:
s[::1]

Out[67]:
'Hello world'
In [68]:
s[::2]

Out[68]:
'Hlowrd'

These technique is called slicing. Read more about the syntax here: http://docs.python.org/release/2.7.3/library/functions.html?highlight=slice#slice

### String formatting¶

Some examples of this subsection are brought from http://docs.python.org/2/tutorial/inputoutput.html

Many operations can be performed over the strings in python. The following command shows the available string operations provided by str objects.

In [69]:
print(dir(str))

['__add__', '__class__', '__contains__', '__delattr__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__getnewargs__', '__getslice__', '__gt__', '__hash__', '__init__', '__le__', '__len__', '__lt__', '__mod__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__rmod__', '__rmul__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '_formatter_field_name_split', '_formatter_parser', 'capitalize', 'center', 'count', 'decode', 'encode', 'endswith', 'expandtabs', 'find', 'format', 'index', 'isalnum', 'isalpha', 'isdigit', 'islower', 'isspace', 'istitle', 'isupper', 'join', 'ljust', 'lower', 'lstrip', 'partition', 'replace', 'rfind', 'rindex', 'rjust', 'rpartition', 'rsplit', 'rstrip', 'split', 'splitlines', 'startswith', 'strip', 'swapcase', 'title', 'translate', 'upper', 'zfill']


The following code shows an example of using the c-style formatting. More formatting specifiers can be found in a c language documentation. A good source: http://www.cplusplus.com/reference/cstdio/printf/.

In [70]:
import math
print 'The value of %5s is approximately %5.3f.' % ('PI', math.pi)

The value of    PI is approximately 3.142.


The following code shows examples of using the format function to control the formatting of the input values to the string

In [71]:
print('{0} and {1}'.format('spam', 'eggs'))
print('{1} and {0}'.format('spam', 'eggs'))

spam and eggs
eggs and spam

In [72]:
print( 'This {food} is {adjective}.'.format(food='spam', adjective='absolutely horrible') )

This spam is absolutely horrible.

In [73]:
print( 'The story of {0}, {1}, and {other}.'.format('Bill', 'Manfred', other='Georg') )

The story of Bill, Manfred, and Georg.

In [74]:
import math
print( 'The value of PI is approximately {0:.3f}.'.format(math.pi) )

The value of PI is approximately 3.142.


Python has a very rich set of functions for text processing. See for example http://docs.python.org/2/library/string.html for more information.

### Exercise 3¶

Use string built-in functions and sliding operation to perform the following over the text of Hello world

• replace the letter o with a. (Hint: use the 'replace' built-in function in the string)
• Convert the first word to upper case letters. (Hint: use the 'upper' built-in function in the string)
• Convert the second word to lower case letters. (Hint: use the 'lower' built-in function in the string)
• Print out the character between the 4th and charachter before last inclusive. (Hint: use slicing operation)
In [75]:
text = "Hello world!"

##### Solution¶
In [76]:
# %load solutions/strings.py


### Lists¶

Lists are very similar to strings, except that each element can be of any type.

The syntax for creating lists in Python is [...]:

In [77]:
l = [1,2,3,4]

print(type(l))
print(l)

<type 'list'>
[1, 2, 3, 4]


We can use the same slicing techniques to manipulate lists as we could use on strings:

In [78]:
print(l)
print(l[1:3])
print(l[::2])

[1, 2, 3, 4]
[2, 3]
[1, 3]


Elements in a list do not all have to be of the same type:

In [79]:
l = [1, 'a', 1.0, 1-1j]
print(l)

[1, 'a', 1.0, (1-1j)]


Python lists can be inhomogeneous and arbitrarily nested:

In [80]:
nested_list = [1, [2, [3, [4, [5]]]]]
print(nested_list)

[1, [2, [3, [4, [5]]]]]


Accessing elements in nested lists

In [81]:
nl = [1, [2, 3, 4], [5, [6, 7, 8]]]

print(nl)
print(nl[0])
print(nl[1][1])
print(nl[2][1][2])

[1, [2, 3, 4], [5, [6, 7, 8]]]
1
3
8


Lists play a very important role in Python, and are for example used in loops and other flow control structures (discussed below). There are number of convenient functions for generating lists of various types, for example the range function:

In [82]:
start = 10
stop = 30
step = 2

range(start, stop, step)

Out[82]:
[10, 12, 14, 16, 18, 20, 22, 24, 26, 28]
In [83]:
# convert a string to a list by type casting:
s2 = list(s)
print s2

['H', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd']

In [84]:
# sorting lists
s2.sort()
print(s2)

[' ', 'H', 'd', 'e', 'l', 'l', 'l', 'o', 'o', 'r', 'w']


#### Adding, inserting, modifying, and removing elements from lists¶

In [85]:
# create a new empty list
l = []

# add an elements using append
l.append("A")
l.append("d")
l.append("d")

print(l)

['A', 'd', 'd']

In [86]:
l[1:3] = ["d", "d"]
print(l)

['A', 'd', 'd']


Remove an element at a specific location using del:

In [87]:
del l[0]
print(l)

['d', 'd']


Using operators with lists

In [88]:
l1 = [1, 2, 3] + [4, 5, 6]
print(l1)

l2 = [1, 2, 3] * 2
print(l2)

[1, 2, 3, 4, 5, 6]
[1, 2, 3, 1, 2, 3]


See help(list) for more details, or read the online documentation

### Exercise 4¶

Perform the following list operations and print the final output

• Create a list of the odd numbers between 4 and 16
• Replace the last element of the list with a list of even numbers between 3 and 9
• At the list in the last element, change the value of the element before last with -1
• Remove elements between the 2nd and 3rd inclusive
• Insert a the string Hello after the first element
##### Solution¶
In [89]:
# %load solutions/lists.py


### Dictionaries¶

Dictionaries are also like lists, except that each element is a key-value pair. The syntax for dictionaries is {key1 : value1, ...}:

In [90]:
params = {"parameter1" : 1.0,
"parameter2" : 2.0,
"parameter3" : 3.0,
1: 4.0,
(5, 'ho'): 'hi'}

print(type(params))
print(params)

<type 'dict'>
{1: 4.0, 'parameter1': 1.0, (5, 'ho'): 'hi', 'parameter3': 3.0, 'parameter2': 2.0}

In [91]:
print("parameter1 = " + str(params["parameter1"]))
print("parameter2 = " + str(params["parameter2"]))
print("parameter3 = " + str(params["parameter3"]))

parameter1 = 1.0
parameter2 = 2.0
parameter3 = 3.0

In [92]:
params["parameter1"] = "A"
params["parameter2"] = "B"

params["parameter4"] = "D"

print("parameter1 = " + str(params["parameter1"]))
print("parameter2 = " + str(params["parameter2"]))
print("parameter3 = " + str(params["parameter3"]))
print("parameter4 = " + str(params["parameter4"]))
print("'key 1' = " + str(params[1]))
print("'key (5, 'ho')' = " + str(params[(5, 'ho')]))

parameter1 = A
parameter2 = B
parameter3 = 3.0
parameter4 = D
'key 1' = 4.0
'key (5, 'ho')' = hi

In [93]:
del params["parameter2"]
print(params)

{'parameter4': 'D', 'parameter1': 'A', 'parameter3': 3.0, 1: 4.0, (5, 'ho'): 'hi'}


### Exercise 5¶

Create a dictionary that uses a string "first last" name of the person as a key and his/her corresponding age as a value for the following list of people

• John Smith 30
• Sara John 2

Perform the following updates to the dictionary

• Increase the age of John by one year
• remove Sara from the dictionary
##### Solution¶
In [94]:
# %load solutions/dicts.py


## Control Flow¶

### Conditional statements: if, elif, else¶

The Python syntax for conditional execution of code use the keywords if, elif (else if), else:

In [95]:
statement1 = False
statement2 = False

if statement1:
print("statement1 is True")

elif statement2:
print("statement2 is True")

else:
print("statement1 and statement2 are False")

statement1 and statement2 are False


For the first time, here we encounted a peculiar and unusual aspect of the Python programming language: Program blocks are defined by their indentation level.

Compare to the equivalent C code:

if (statement1)
{
printf("statement1 is True\n");
}
else if (statement2)
{
printf("statement2 is True\n");
}
else
{
printf("statement1 and statement2 are False\n");
}



In C blocks are defined by the enclosing curly brakets { and }. And the level of indentation (white space before the code statements) does not matter (completely optional).

But in Python, the extent of a code block is defined by the indentation level (usually a tab or say four white spaces). This means that we have to be careful to indent our code correctly, or else we will get syntax errors.

Examples:

In [96]:
statement1 = False

if statement1:
print("printed if statement1 is True")

print("still inside the if block")

In [97]:
if statement1:
print("printed if statement1 is True")

print("now outside the if block")

now outside the if block

In [98]:
# a compact way for using the if statement
a = 2 if statement1 else 4
print("a= ", a)

('a= ', 4)

In [99]:
name = 'john'
if name in ['jed', 'john']:
print("We have Jed or John")

num = 1
if num in [1, 2]:
print("We have 1 or 2")

We have Jed or John
We have 1 or 2


## Loops¶

In Python, loops can be programmed in a number of different ways. The most common is the for loop, which is used together with iterable objects, such as lists. The basic syntax is:

for loops:

In [100]:
for x in [1,2,3]:
print(x)

1
2
3


The for loop iterates over the elements of the supplied list, and executes the containing block once for each element. Any kind of list can be used in the for loop. For example:

In [101]:
for x in range(4): # by default range start at 0
print(x)

0
1
2
3


Note: range(4) does not include 4 !

In [102]:
for x in range(-3,3):
print(x)

-3
-2
-1
0
1
2

In [103]:
for word in ["scientific", "computing", "with", "python"]:
print(word)

scientific
computing
with
python


To iterate over key-value pairs of a dictionary:

In [104]:
for key, value in params.items():
print(key + " = " + str(value))

parameter4 = D
parameter1 = A
parameter3 = 3.0

---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-104-1802f5779f7e> in <module>()
1 for key, value in params.items():
----> 2     print(key + " = " + str(value))

TypeError: unsupported operand type(s) for +: 'int' and 'str'

Sometimes it is useful to have access to the indices of the values when iterating over a list. We can use the enumerate function for this:

In [105]:
for idx, x in enumerate(range(-3,3)):
print(idx, x)

(0, -3)
(1, -2)
(2, -1)
(3, 0)
(4, 1)
(5, 2)


while loops:

In [106]:
i = 0

while i < 5:
print(i)

i = i + 1

print("done")

0
1
2
3
4
done


Note that the print("done") statement is not part of the while loop body because of the difference in indentation.

### Exercise 6¶

Loop through the following list of words and create a dictionary according to the following rules:

• Add a word to the dictionary if its length is greater than 2.
• Word lengths should be the keys, lists of words with corresponding lengths should be the values. In other words, for every key in the dictionary its value is a list of words with the same length as the key.
In [107]:
words = ["Aerial", "Affect", "Agile", "Agriculture", "Animal", "Attract", "Audubon",
"Backyard", "Barrier", "Beak", "Bill", "Birdbath", "Branch", "Breed", "Buzzard",
"The", "On", "Upper", "Not", "What", "Linked", "Up", "In", "A", "lol"]

##### Solution¶
In [108]:
# %load solutions/control_flow.py


## Functions¶

A function in Python is defined using the keyword def, followed by a function name, a signature within parentheses (), and a colon :. The following code, with one additional level of indentation, is the function body.

In [109]:
def func0():
print("test")

In [110]:
func0()

test


Optionally, but highly recommended, we can define a so called "docstring", which is a description of the functions purpose and behaivor. The docstring should follow directly after the function definition, before the code in the function body.

In [111]:
def func1(s):
"""
Print a string 's' and tell how many characters it has
"""

print(s + " has " + str(len(s)) + " characters")
return 1, 2, 3

In [112]:
help(func1)

Help on function func1 in module __main__:

func1(s)
Print a string 's' and tell how many characters it has


In [113]:
func1("test")

test has 4 characters

Out[113]:
(1, 2, 3)

We can return multiple values from a function using tuples (see above):

In [114]:
def powers(x):
"""
Return a few powers of x.
"""
return x ** 2, x ** 3, x ** 4

In [115]:
powers(3)

Out[115]:
(9, 27, 81)
In [116]:
x2, x3, _ = powers(3)

print(x3)

27


### Default argument and keyword arguments¶

In a definition of a function, we can give default values to the arguments the function takes:

In [117]:
def myfunc(x, p=2, debug=False):
if debug:
print("evaluating myfunc for x = " + str(x) + " using exponent p = " + str(p))
return x**p


If we don't provide a value of the debug argument when calling the the function myfunc it defaults to the value provided in the function definition:

In [118]:
myfunc(5)

Out[118]:
25
In [119]:
myfunc(5, debug=True)

evaluating myfunc for x = 5 using exponent p = 2

Out[119]:
25

If we explicitly list the name of the arguments in the function calls, they do not need to come in the same order as in the function definition. This is called keyword arguments, and is often very useful in functions that takes a lot of optional arguments.

In [120]:
myfunc(p=3, debug=True, x=7)

evaluating myfunc for x = 7 using exponent p = 3

Out[120]:
343