a = 5.
print(id(a))
b = 5.
print(id(b))


"""
Explanation: Some words on equality
A variable in python stores the reference to a register in the memory, not the actual value. Each variable has a unique id.
End of explanation
"""


c = a
print id(c)
print c is a
print c == a
print b == a
print b is c

print(c)
print c is a
c = 4.
print(c)
print(a)
print c is a


# let's do some changes
c += 2.
print(c)
print c is a

print c
c -= 2.
print(c, a)
print c is a
print c == a

"""
Explanation: If you assign a variable, the ID is passed. This means that the same object has just only two different names, but it is still the same object. This saves memory.
End of explanation
"""


s1 = 'hello'
s2 = 'world'
print(s1 is s2)
print(s1 == s2)

s3 = s1
print s1 is s3


s4 = 'hello'  
print(s1 is s4)   # note that even a new variable is generated, while its contents already exists, just a pointer is used
print(s1 == s4)
print(id(s1),id(s4))

s4 += ' geography'
print(s4)
print(id(s4))
print(s4 is s1)

"""
Explanation: Remember

The is function checks if the ID of two objects are the same.
The = operator checks if the numerical value is the same

How is it for strings?
End of explanation
"""


import numpy as np # we talk about numpy later today
A = np.array([[1, 2], [3, 4]])
A

B=A*1.   # copy, deepcopy
B

print id(A), id(B)

B[0,0]=10.
B

"""
Explanation: Always be aware that an assignment might be just a pointer!
End of explanation
"""


A

C = A
C[1,1] = 77.

B

"""
Explanation: Note what happened to A now ...
End of explanation
"""


def foo(a,b):
    print(a + ' ' + b)
    
a = 'Hello'
b = 'World'
foo(a,b)

def foo1(a,b):
    c = a+b
    a = 'Munich'
    print(c)
    
foo1(a,b)
print(a)  # the original variable was unchanged

"""
Explanation: Where does it matter in particular? Working with functions
End of explanation
"""


