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]:
# More Information about numeric datatypes

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]:

Control-Flow

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]:
# helpful modules
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 [ ]: