var1 = 1              # interger
var2 = 2.34           # floating point numbers
var3 = 5.6 + 7.8j     # complex numbers 
var4 = "Hello World"  # strings
var5 = True           # booleans
var6 = None           # special value to indicate the absence of a value

print("var1 value:", var1, "type:", type(var1))
print("var2 value:", var2, "type:", type(var2))
print("var3 value:", var3, "type:", type(var3))
print("var4 value:", var4, "type:", type(var4))
print("var5 value:", var5, "type:", type(var5))
print("var6 value:", var6, "type:", type(var6))

"""
Explanation: <img class="logo" src="images/python-logo.png" height=100 align='right'/>
Python

High-level
General purpose
Multiple programming paradigms
Interpreted

Variables
End of explanation
"""


hydrometeors = ['rain', 'snow', 'hail']  # create a list holding three elements
print(hydrometeors)
print('length:', len(hydrometeors))

"""
Explanation: Containers
Data types for holding many variables
Lists
One-dimensional, ordered container whose contents and length can change (mutable).
End of explanation
"""


mixed_type_list = ['rain', 4.5, 99, None]
print(mixed_type_list)

"""
Explanation: The elements of a list do not need to be of the same type:
End of explanation
"""


hydrometeors = ['rain', 'snow', 'hail']
hydrometeors.append('drizzle')  # add 'drizzle' to the end of the list
print(hydrometeors)

hydrometeors = ['rain', 'snow', 'hail']
hydrometeors.insert(1, 'graupel')  # insert graupel before position 1
print(hydrometeors)

hydrometeors = ['rain', 'snow', 'hail']
del hydrometeors[0]  # remove the first element from the list
print(hydrometeors)

hydrometeors = ['rain', 'snow', 'hail']
observation = hydrometeors.pop()  # remove the last item from the list and store it in hydrometeor
print("observation:", observation)
print("hydrometeors:", hydrometeors)

"""
Explanation: Elements can be added or removed from a list
End of explanation
"""


hydrometeors = ['rain', 'snow', 'hail']
print("Before change:", hydrometeors)
hydrometeors[0] = 'virga'
print("After change:", hydrometeors)

"""
Explanation: Elements of a list can be changed
End of explanation
"""


hydrometeors = ['rain', 'snow', 'hail']
print('index 0:', hydrometeors[0])   # indexing begins at 0
print('index 1:', hydrometeors[1])
print('index 2:', hydrometeors[2])

hydrometeors[3]  # Trying to access elements which do not exist raises a IndexError

hydrometeors = ['rain', 'snow', 'hail']
print('index -1:', hydrometeors[-1])
print('index -2:', hydrometeors[-2])
print('index -3:', hydrometeors[-3])

"""
Explanation: Lists Indexing
End of explanation
"""


hydrometeors = ['rain', 'snow', 'hail', 'drizzle', 'graupel', 'virga']
print(hydrometeors[2:4])  # select elements from index 2 to index 4

hydrometeors[:3]  # start from beginning

hydrometeors[3:]  # until the end

hydrometeors[3:-1]  # negative indices

hydrometeors[1::2]  # every 2nd element

"""
Explanation: List slicing
Syntax: list_variable[start:end:step]
End of explanation
"""


t = ('rain', 'snow', 'hail')
print(t)
print(len(t))

t[0] = 'virga'  # tuples cannot be changed

"""
Explanation: Tuples
One-dimensional, ordered container whose contents and length CANNOT change (immutable).
End of explanation
"""


observations = ('rain', 'snow', 'hail')  # tuple with three elements
obs1, obs2, obs3 = observations    # unpack tuple into obs1, obs2, obs3 variables
print("observations:", observations)
print("obs1:", obs1)
print("obs2:", obs2)
print("obs3:", obs3)

"""
Explanation: Can be 'unpacked' to assign variable.  Often used with functions which return multiple items.
End of explanation
"""


d = {'site': 'KLOT', 'amount': 20, 'wind': 'east'} 

print(d.keys())

print(d.values())

print('site:', d['wind'])
print('amount:', d['amount'])
print('wind:', d['wind'])


print("wind before change:", d['wind'])
d['wind'] = 'west'
print("wind after change:", d['wind'])

"""
Explanation: Dictionaries
Unordered collection of key/value pairs whose size and content can change
End of explanation
"""


d = {'site': 'KLOT', 'amount': 20, 'wind': 'east'} 
print(d)

del d['wind']
print(d)

d['wind_speed']  = 'east'
d['wind_direction'] = '10 m/s'
print(d)

"""
Explanation: Entries can be added or remove from dictionaries
End of explanation
"""


hydrometeor = 'rain'
if hydrometeor == 'rain':
    print("You saw rain")

hydrometeor = 'hail'
if hydrometeor == 'rain':
    print("You saw rain")
else:
    print("You did NOT see rain")

hydrometeor = 'snow'
if hydrometeor == 'rain':
    print("You saw rain")
elif hydrometeor == 'snow':
    print("You saw snow")
else:
    print("I do not know what you saw")

"""
Explanation: Note: Dictionaries do not preserve the order in which entries are added.  If you need ordering use a OrderedDict from the collections module.
Flow control
If statements
End of explanation
"""


hydrometeors = ['rain', 'snow', 'hail']
for hydrometeor in hydrometeors:  # loop over elements in a list
    print(hydrometeor)

for i in range(5):  # loop over the number 0 to 4
    print(i)

d = {'site': 'KLOT', 'amount': 20, 'wind': 'east'} 
for key, value in d.items():
    print(key, ':', value)

"""
Explanation: for loops
Syntax: <br/>
for variable in iterable:<br/>
&nbsp;&nbsp;&nbsp;&nbsp;code block
End of explanation
"""


# simple
def func(arg1):
    print(arg1)
    return 42

# call a function
return_value = func("Hello World")
print("ret_value:", return_value)

"""
Explanation: Functions
End of explanation
"""


def add_numbers(number1, number2):
    return number1 + number2

def say_hello():
    print("Hello AMS")
    
def favorite_hydrometeor(name, hydrometeor='snow'):
    print("Hello", name)
    print("Your favorite hydrometeor is", hydrometeor)

print(add_numbers(1, 2))

say_hello()

favorite_hydrometeor("Jonathan")

favorite_hydrometeor("Jonathan", hydrometeor="hail")

"""
Explanation: Functions can have multiple, no and even default arguments
End of explanation
"""


def sum_and_product(a, b):
    return a+b, a*b
sum_ab, product_ab = sum_and_product(2, 3)
print("sum", sum_ab)
print("product", product_ab)

"""
Explanation: Functions can return multiple values:
End of explanation
"""


class Point(object):
    """ A class to store the coordinate in a plane"""
    
    def __init__(self, x, y):
        self.x = x   # an attribute
        self.y = y   # an attribute
        
    def sum_of_coordinates(self):  # a class method
        return self.x + self.y

home = Point(2, 3)

print(home.x)
print(home.y)

home.sum_of_coordinates()

"""
Explanation: Classes
End of explanation
"""


import math  # import the entire math module

math.sqrt(2)

from random import randrange   # import just the randrange function from the random module

for i in range(5):
    print(randrange(1, 10))

"""
Explanation: Libraries

Python has a large number of libraries which extend the basic functionality.
The standard library is included with Python and contains a number of helpful features.
Third-party libraries can add even more powerful functionality!
Libraries must be imported to be used.
End of explanation
"""


