################## Lists ############################
# lists are simple data structures that can hold different data types

a = [1,2,'hallo']
print a

# lists are accessed by indices, starting with 0
print a[0]

a[0] = 5

print a

# lists can be indexed with slices, first index is included, the last is not
print a[0:2]

# if the index is ommitted, then the maximal or minimal index is taken
print a[1:]
print a[:1]

# negative indices count downwards from the maximal index
print a[:-1]

# one can also specify steps in slices (start:stop:step)
print a[0:3:2]
print a[1::2]

# if new variables are assigned to an existing list, the list is NOT copied
b = a
b[2] = 0
print a

# if you want to copy lists, use
b = list(a)
b[2] = 'new stuff'
print a
print b
# lists of lists
b = [1,2,3, [4,3,5]]
print b[3][1:]

################### Tuples #####################################
# tuples are constant lists. They behave basically like lists but don't allow elements to be set
b = (1,2,'hello')
print b
print b[::2]
# b[2] = "test"  # error!

################### Dictionaries ###############################
# Dictionaries are like lists that can be accessed with arbitraty
# keys. They are initialized with curly brackets and key:value pairs
c = {'key1':2, 3.4:'something else', 5:6}
print c.keys()
print c.values()
print c.items()
print c
print c['key1']
c[3.4] = 'again something else'
print c

# again, dictionaries are not copied
d = c
d[5] = 8
print c


############## Numerical types ##################################
# mostly, python determines the numerical type of a number. However,
# sometimes one needs to pay attention when dealing with integers

a = 1
b = 5
print a/b

# initialization as float or the function float(a) help
a = 1.
b = 5.
print a/b