Datatypes and Control-Flow

# Datatypes

## Numeric Types: `int`, `long`, `float`, `complex`, `bool`

• int: 32 bit
• long: unlimited precision
• float: 64 bit
• complex: real float and imaginary float
• bool: `True` and `False`
``````

In [1]:

# The "hash-mark" indicates the start of a comment
# Python automatically assigns the right type:

a = 3 # Another Comment
b = 1.1
c = 4 + 6j
print(type(a), type(b), type(c))

``````
``````

(<type 'int'>, <type 'float'>, <type 'complex'>)

``````
``````

In [2]:

# Mixing types in an arithmetic expression
# will yield the "wider" type

print(b * 5, type(b * 5))
print (b + c, type(b + c))

``````
``````

(5.5, <type 'float'>)
((5.1+6j), <type 'complex'>)

``````

Integer division yields integer!

• add decimal point, or
• cast explicitly (eg. `float()`)
``````

In [3]:

print(a / 4, a / 4.0, float(a) / 4)

``````
``````

(0, 0.75, 0.75)

``````
``````

In [4]:

# The Boolean Type: `bool`
test = 3 > 4
tost = 5 != 9
print(test, type(test))
print(tost, type(tost))

``````
``````

(False, <type 'bool'>)
(True, <type 'bool'>)

``````
``````

In [5]:

from IPython.display import HTML
HTML('<iframe src="https://docs.python.org/2/library/stdtypes.html#numeric-types-int-float-long-complex" width=700 height=350></iframe>')

``````
``````

Out[5]:

``````

## Strings

• double quote (`"`) and single quotes (`'`) are synonymous.
• triple quotes (`'''`) preserve line endings.
• the backslash (`\`) is the escape-character.
``````

In [6]:

s1 = 'He\'s a lumberjack, and he\'s okay.\nHe sleeps all night and he works all day.'

s2 = '''I cut down trees. I eat my lunch.
I go to the lavatory.
On Wednesdays I go shoppin'
And have buttered scones for tea.'''

print(s1)
print
print(s2)

``````
``````

He's a lumberjack, and he's okay.
He sleeps all night and he works all day.

I cut down trees. I eat my lunch.
I go to the lavatory.
On Wednesdays I go shoppin'
And have buttered scones for tea.

``````
• concatenate with "`+`"
• format using `format()` - method
``````

In [7]:

('{:.4f} is a {}'.format(pi,'float') +
' and "a = {}" needs no formatting in excercise {:02d}.'.format(3.1,1))

# Btw. : line-breaks inside brackets are implicitly continued

``````
``````

Out[7]:

'3.1416 is a float and "a = 3.1" needs no formatting in excercise 01.'

``````
``````

In [8]:

# More on the format-specification
from IPython.display import HTML
HTML('<iframe src="https://docs.python.org/2/library/string.html#format-specification-mini-language" width=700 height=350></iframe>')

``````
``````

Out[8]:

``````
• strings support indexing
• and slicing
``````

In [9]:

s = "0123456789"
index0 = s[0]
index9 = s[9]
print("Index zero: {}, index nine: {}".format(index0, index9))

``````
``````

Index zero: 0, index nine: 9

``````

Note:

• Indices start with 0. as in C, unlike Fortran, Matlab, R.
• index `i` retuns the (`i+1`)st character.
``````

In [10]:

# Negative indices count from the end
# Slice using "[start:stop:step]"
# Any of "start", "stop", "step" can be omitted
# They default to 0, len(string), 1, respectively
s = "0123456789"
print(s[-1], s[-2], s[0:2], s[0:9], s[0:10], s[:], s[:3], s[3:],s[::2])

``````
``````

('9', '8', '01', '012345678', '0123456789', '0123456789', '012', '3456789', '02468')

``````

Note: Strings are "immutable"

``````

In [11]:

s = "0123456789"
s[0] = 1

``````
``````

---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-11-e2e75c59f7f6> in <module>()
1 s = "0123456789"
----> 2 s[0] = 1

TypeError: 'str' object does not support item assignment

``````

There are a largne number of string methods.
Examples:

``````

In [12]:

'Py' in 'Oython'

``````
``````

Out[12]:

False

``````
``````

In [13]:

'Python'.find('tho')

``````
``````

Out[13]:

2

``````
``````

In [14]:

s.isdigit()

``````
``````

Out[14]:

True

``````
``````

In [15]:

words = array("Words usually are obtained  by splitting at    whitespace".split())
nowords = "Words usually are obtained  by splitting at    whitespace".split('a')
print(words)
print(nowords)
type(words)

``````
``````

['Words' 'usually' 'are' 'obtained' 'by' 'splitting' 'at' 'whitespace']
['Words usu', 'lly ', 're obt', 'ined  by splitting ', 't    whitesp', 'ce']

Out[15]:

numpy.ndarray

``````
``````

In [16]:

'_'.join(words)

``````
``````

Out[16]:

'Words_usually_are_obtained_by_splitting_at_whitespace'

``````

Ipython Trick
Get a list of all available methods for an object by writing "`objectname.`" and hitting [TAB].
Try "`words.`[TAB]" Also "`str.`[TAB]"

``````

In [16]:

``````
``````

In [17]:

# Documentation of string methods
from IPython.display import HTML
HTML('<iframe src="https://docs.python.org/2/library/stdtypes.html#string-methods" width=700 height=350></iframe>')

``````
``````

Out[17]:

``````
``````

In [17]:

``````
5 minutes to play with numeric types, strings and formatting
``````

In [17]:

``````

## Lists

• Lists are very powerful in Python.
• Lists can contain any mixture of objects.
• The list is an ordered container.
``````

In [18]:

L = ['red', 2, 'blue', 3, 'green', 9.9, 'black', 0.7, 'white', -5]
type(L)

``````
``````

Out[18]:

list

``````
``````

In [19]:

# Indexing and slicing just as for strings

print(L[0])
print(L[-1:3:-1])

``````
``````

red
[-5, 'white', 0.7, 'black', 9.9, 'green']

``````
``````

In [20]:

# Reverse a list

L[::-1]

``````
``````

Out[20]:

[-5, 'white', 0.7, 'black', 9.9, 'green', 3, 'blue', 2, 'red']

``````

Note: Lists are "mutable"

``````

In [21]:

L = ['red', 2, 'blue', 3, 'green', 9.9, 'black', 0.7, 'white', -5]
L[2:6] = ['violet',4,'turquois',10.1]
L

``````
``````

Out[21]:

['red', 2, 'violet', 4, 'turquois', 10.1, 'black', 0.7, 'white', -5]

``````
``````

In [22]:

# removing elements
del(L[4:6])
L

``````
``````

Out[22]:

['red', 2, 'violet', 4, 'black', 0.7, 'white', -5]

``````
``````

In [23]:

# remove an get last element
L = ['red', 2, 'blue', 3, 'green', 9.9, 'black', 0.7, 'white', -5]
print(L)
l1 = L.pop()
print(l1)
print(L)
print(L.sort())

``````
``````

['red', 2, 'blue', 3, 'green', 9.9, 'black', 0.7, 'white', -5]
-5
['red', 2, 'blue', 3, 'green', 9.9, 'black', 0.7, 'white']
None

``````
``````

In [24]:

# insert element at index
L.insert(3,'between3, blue and 3')
print(L)

``````
``````

[0.7, 2, 3, 'between3, blue and 3', 9.9, 'black', 'blue', 'green', 'red', 'white']

``````
``````

In [25]:

# append and extend
L = ['red', 2, 'blue', 3, 'green', 9.9, 'black', 0.7, 'white', -5]
print('original:{}'.format(L))
L1 = [1,'other','list']
L.append(L1)
print('append: {}'.format(L))
L.extend(L1)
print('extend:{}'.format(L))
L = L + L1
print('concatenated: {}'.format(L))
L.extend(L1)

``````
``````

original:['red', 2, 'blue', 3, 'green', 9.9, 'black', 0.7, 'white', -5]
append: ['red', 2, 'blue', 3, 'green', 9.9, 'black', 0.7, 'white', -5, [1, 'other', 'list']]
extend:['red', 2, 'blue', 3, 'green', 9.9, 'black', 0.7, 'white', -5, [1, 'other', 'list'], 1, 'other', 'list']
concatenated: ['red', 2, 'blue', 3, 'green', 9.9, 'black', 0.7, 'white', -5, [1, 'other', 'list'], 1, 'other', 'list', 1, 'other', 'list']

``````

VERY USEFUL: List comprehension

• replaces one or multiple loops to apply functions to list elements
• filter the list at the same time
``````

In [26]:

x = range(0,10)
# apply to each element
y2 = [y**2 for y in x]
# complicated functions can be applied
x3 = [y/2.0 if y >= 25 else sqrt(y) for y in x2]
# filter
x4 = [y for y in x3 if y % 2 == 0]
print(x)
print(x2)
print(x3)
print(x4)

``````
``````

---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
<ipython-input-26-14676a93f58a> in <module>()
3 y2 = [y**2 for y in x]
4 # complicated functions can be applied
----> 5 x3 = [y/2.0 if y >= 25 else sqrt(y) for y in x2]
6 # filter
7 x4 = [y for y in x3 if y % 2 == 0]

NameError: name 'x2' is not defined

``````

## Tuples and Sets

### Tuples

• similar to lists,
• but immutable
``````

In [27]:

t = ('hello',1,'triple')
print(type(t))
t
print(type([t]))

``````
``````

<type 'tuple'>
<type 'list'>

``````

### Sets

• unordered
• mutable
• unique entries
``````

In [28]:

s = set(("a",4,"b",5))
print(type(s))
s1 = set((7,5,"c","b",7,"b"))
union = s | s1
intersect = s & s1
print("s1: {}".format(s1))
print("union: {}".format(union))
print("intersect: {}").format(intersect)
l1 = list(s1)
print(l1)
l1.sort()
print(l1)

``````
``````

<type 'set'>
s1: set(['c', 'b', 5, 7])
union: set(['a', 'c', 'b', 4, 5, 7])
intersect: set(['b', 5])
['c', 'b', 5, 7]
[5, 7, 'b', 'c']

``````
``````

In [28]:

``````

<span style="background-color:grey" # 5 Minutes to play with lists, sets and tuples</span>

5 minutes to play with lists, tuples and sets
``````

In [28]:

``````

## Dictionaries

• A dictionary maps keys to values
• The dictionary is an unordered container
• Use it to store and retrieve values associated with a name.
• Keys can be of any immutable datatype (e.g. numbers, strings)
• Values can be anything
``````

In [29]:

numbers = { "jack": 04377465, "john": 97264384, "ralph":['+41 76 873274',937283] }
print(type(numbers))
numbers
# Observe how Jack's number get interpreted (as octal)

``````
``````

<type 'dict'>

Out[29]:

{'jack': 1179445, 'john': 97264384, 'ralph': ['+41 76 873274', 937283]}

``````
``````

In [30]:

numbers = { "jack": 04377465, "john": 97264384, "ralph":['+41 76 873274',937283] }
print(numbers)
print(numbers["john"])     # access by name
print(numbers["ralph"][0]) # concatenate accessors for contained objects
numbers["jenny"] = 9374    # add new entries
del(numbers["jack"])       # delete entries
numbers

``````
``````

{'john': 97264384, 'ralph': ['+41 76 873274', 937283], 'jack': 1179445}
97264384
+41 76 873274

Out[30]:

{'jenny': 9374, 'john': 97264384, 'ralph': ['+41 76 873274', 937283]}

``````
``````

In [31]:

# "in" and "not in" work for all containers
print('ralph' in numbers)
print('ralph' not in numbers)
print(97264384 in numbers.values())
[str(x) + 'MODIFIED' for x in numbers.values()]

``````
``````

True
False
True

Out[31]:

['97264384MODIFIED', "['+41 76 873274', 937283]MODIFIED", '9374MODIFIED']

``````
``````

In [32]:

# Another way to construct dictionaries:
d = dict([(1,"one"), (2,"two"), (3,"three"), (4,"four")])
d

``````
``````

Out[32]:

{1: 'one', 2: 'two', 3: 'three', 4: 'four'}

``````
``````

In [33]:

# From lists to dictionaries
l1 = ["These","are","words","in","a","sentence"]
l2 = range(0,len(l1))
# Note: "len()" gives the number of elements of any container type

# zip creates a list of corresponding pairs of two lists with equal length
pairs = zip(l1,l2)
dicty = dict(pairs)

print("l1 : {}".format(l1))
print("l2 : {}".format(l2))
print("pairs : {}".format(pairs))
print("dicty : {}".format(dicty))

``````
``````

l1 : ['These', 'are', 'words', 'in', 'a', 'sentence']
l2 : [0, 1, 2, 3, 4, 5]
pairs : [('These', 0), ('are', 1), ('words', 2), ('in', 3), ('a', 4), ('sentence', 5)]
dicty : {'a': 4, 'sentence': 5, 'These': 0, 'are': 1, 'words': 2, 'in': 3}

``````
``````

In [34]:

# There are more dictionary methods
from IPython.display import HTML
HTML('<iframe src="https://docs.python.org/2/library/stdtypes.html#dict" width=700 height=350></iframe>')

``````
``````

Out[34]:

``````

# if - elif - else

• just as you would expect
``````

In [35]:

n = 23
a = range(0,11)
if n in a:
print("In")
elif n == 23:
print("Should be in")
else:
print("{} is a bad number.".format(n))

``````
``````

Should be in

``````
• Blocks of code are identified by indentation (4 spaces)!
• This is a feature that tends to irritate beginners sometimes
• Get used to it and enjoy less bracket-cluttered code
``````

In [36]:

# The "ternary operator"
n = 2
a = range(0,11)
x = "In" if n in a else "Bad number"
print(x)

``````
``````

In

``````

## Iteration

• nothing new here
• "break" and "continue" work as expected
``````

In [37]:

# for

for i in range(20,31):
print(i**2),

# Note: The comma at the end of the "print" statement suppress printing of a newline at the end.

``````
``````

400 441 484 529 576 625 676 729 784 841 900

``````
``````

In [38]:

# while

q = 10
while q <= 900:
q += q*3
print(q),

``````
``````

40 160 640 2560

``````

Reminder: Use list-comprehension if possible!

``````

In [39]:

# dict.iteritems()
# iterating over keys *and* values of dictionaries

d = dict([(1,"one"), (2,"two"), (3,"three"), (4,"four")])
for k, v in d.iteritems():
print("Key: {}, Value: {}".format(k, v))

# Note a tuple T (or list) on the right hand side of an assignment
# can be directly assigned to len(T) individual variables on the left hand side.
a, b, c, d = (1,2,3,4)
print(a,b,c,d)

``````
``````

Key: 1, Value: one
Key: 2, Value: two
Key: 3, Value: three
Key: 4, Value: four
(1, 2, 3, 4)

``````
``````

In [40]:

# enumerate(list)
# iterate over list and list-index at the same time

l1 = ["These","are","words","in","a","sentence"]
for i, x in enumerate(l1):
print("Index = {}; Item = {}".format(i,x))

``````
``````

Index = 0; Item = These
Index = 1; Item = are
Index = 2; Item = words
Index = 3; Item = in
Index = 4; Item = a
Index = 5; Item = sentence

``````
``````

In [40]:

``````
``````

In [40]:

``````

# Functions

• Functions are "first-class-citizens":
They can be passed as a parameter, returned from a function,
assigned to a variable, and put into containers.
• The usual scope-rules apply: Local, Enclosing, Global, Builtin.
• Functions can be nested in functions.
``````

In [41]:

# Function definition

def my_function(a, b, c):
print(a, b, c)
res = (a + b)**c
return(res)

my_function(2, 3, 1.123)

``````
``````

(2, 3, 1.123)

Out[41]:

6.094573442517905

``````

There are required positional- and optional keyword- parameters (just like in R)

``````

In [42]:

def my_func2(a, b, default=1):
print(a, b, default)
res = (a + b)**default
return(res)

print(my_func2(2,3))
print(my_func2(2, 3, 1.123))

``````
``````

(2, 3, 1)
5
(2, 3, 1.123)
6.09457344252

``````
5 minutes to play with dictionaries, control-flow and functions

# A little exercise

In the next session, we need several files from the ERA-Interim reanalysis dataset.
Write a function that takes year, month, startday, and endday as parameters, and returns list a of corresponding Z-level filenames (with absolute paths). The input parameters have to be numeric (not string).

``````

In [43]:

# The path to erainterim
root = '/net/atmos/data/erainterim/cdf'

# below that directory the path is <year>/<month>/.
# <year> has values from 1979 - 2014, <month> from 01 - 12.
# Under the <month> directory is a large number of files.
# The Z-files have the form:
# Z<year><month><day>_hour
# For example:
# <root>/2010/09/Z20100903_18
# refers to Sept. 3, 2010, 18:00h

``````
``````

In [44]:

import os.path
import glob

# example parameters
startday = 3
endday = 8
month = 9
year = 2010

# your function here:

files = get_zfile(startday, endday, month, year)
print(files)

``````
``````

---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
<ipython-input-44-28515c5f0ffa> in <module>()
14
15
---> 16 files = get_zfile(startday, endday, month, year)
17 print(files)

NameError: name 'get_zfile' is not defined

``````
``````

In [ ]:

``````