def hello(a,b):
    return a+b

hello(1,1)

hello('a','b')

"""
Explanation: Functions
Functions are defined as
def function_name(parameters):
End of explanation
"""


def Fibonacci(n):
    if n < 2: 
        return n
    else: 
        return Fibonacci(n-1)+Fibonacci(n-2)
print Fibonacci(10)

def Fibonacci(n):
    return n if n < 2 else Fibonacci(n-1)+Fibonacci(n-2)
print Fibonacci(10)

"""
Explanation: Recursive function
recursive function is an easy way to solve some mathemtical problems but performance varies. The following is an example of a recursive function calculating the nth number in the Fibonacci Sequence.
End of explanation
"""


class Person:
    def __init__(self,age,salary):
        self.age = age
        self.salary = salary
    def out(self):
        print self.age
        print self.salary

"""
Explanation: Class
Class is a blueprint defining the charactaristics and behaviors of an object. 
python
class MyClass:
    ...
    ...
For a simple class, one shall define an instance
python
__init__()
to handle variable when it created. Let's try the following example:
End of explanation
"""


a = Person(30,10000)
a.out()

"""
Explanation: This is a basic class definition, the age and salary are needed when creating this object. The new class can be invoked like this:
End of explanation
"""


a = 'Alice'
print a
def change_my_name(my_name):
    my_name = 'Bob'
change_my_name(a)
print a

a = 'Alice'
print a
def change_my_name(my_name):
    my_name = 'Bob'
    return my_name
b = change_my_name(a)
print b

"""
Explanation: The __init__ initilaze the variables stored in the class. When they are called inside the class, we should add a self. in front of the variable. The out(Self) method are arbitary functions that can be used by calling Yourclass.yourfunction(). The input to the functions can be added after the self input.
Scope of variables
Very important: "call-by-value" or "call-by-reference"?
It is not a simple question, it often confused many people..We now try to do some testing..
End of explanation
"""


a_list_of_names = ['Alice','Bob','Christ','Dora']
print a_list_of_names

def change_a_value(something):
    something[0] = 'Not Alice'
    
change_a_value(a_list_of_names)
print a_list_of_names

"""
Explanation: So is it "call-by-value"? The value does not changed?
But Try this:
End of explanation
"""


a_list_of_names = ['Alice','Bob','Christ','Dora']
print a_list_of_names
a_new_list_of_names = a_list_of_names
print a_new_list_of_names

def change_a_value(something):
    something[0] = 'Not Alice'
change_a_value(a_list_of_names)

print "After change_a_value:"
print a_list_of_names
print a_new_list_of_names

print "Is 'a_new_list_of_names' same as 'a_list_of_names' ?"
print a_new_list_of_names is a_list_of_names

"""
Explanation: Confused? Why the list is changeable but the string is not?
End of explanation
"""


some_guy = 'Alice'
a_list_of_names = []
a_list_of_names.append(some_guy)
print "Is 'some_guy' same as the first element in a_list_of_names ?"
print (some_guy is a_list_of_names[0])

another_list_of_names = a_list_of_names
print "Is 'a_list_of_names' same as the 'another_list_of_names' ?"
print (a_list_of_names is another_list_of_names)

some_guy = 'Bob'
another_list_of_names.append(some_guy)
print "We have added Bob to the list, now is 'a_list_of_names' same as the 'another_list_of_names' ? "
print (a_list_of_names is another_list_of_names)

print (some_guy,a_list_of_names,another_list_of_names)
some_guy = 'Christ'
print (some_guy,a_list_of_names,another_list_of_names)

"""
Explanation: More Confused? Why the function return the same object, is it say that it is call-by-reference?
End of explanation
"""


