Week 1, Day 2 (Python for Data Science)
Welcome to second day (Week 1) of the McE-51069 course. We will introduce the basics of Python programming language and share you necessary lectures and assignment notebooks.
- Notebooks and Assignments
- Learning Tips
- Data Types
- Data Structures
- Conditionals & Loops in Python
- Functions
- Classes
Notebooks and Assignments
Please download all the lectures and assignment notebooks of week 1 (Day 2) here. We have also posted a guide video on downloading & accessing materials on our youtube channel.
Data Types
In python, there are built-in data-types, some of which are described below:
- Int (1 ,100, 99)
- Float (1.0, 3.14, 2.718)
- String ("Myanmar", "Burma")
- Boolean (True, False)
- Complex (1+0j)
- null (None)
To describe the various properties in the real world, we must use different data types.
e.g., if we want to describe a person's name
, we could use String
.
Int
for his/her age, Float
for his/her height in (cm) and Boolean
if he/she is graduated or not.
The main take away from this lecture notebook is to know the differences between data types and their usage.
Four Most Used Data Types
We can store data of different types in variable names. See the example below:
# Int
int1 = 5
int2 = 3
# Float
float1 = 1.
float2 = 3.14
# String
string1 = "Hello"
string2 = 'World'
# Boolean
bool1 = True
bool2 = False
print
function is used to print the values of the variable to the output screen.
print(int1)
5
We can check the datatype of the variable by using type
function:
type(int1)
int
int1 = 5
int2 = 3
# We can add, subtract two elements of 'Int' dtype.
print(int1 + int2) # Addition
print(int1 - int2) # Subtraction
print(int1 * int2) # Multiplication
print(int1 / int2) # Division
print(int1 % int2) # Remainder
print(int1**int2) # Power
print("")
float1 = 1.
float2 = 3.14
# We can also, do operations on `Float` dtype.
print(float1 + float2)
print(float1 - float2)
print(float1 * float2)
print(float1 / float2)
print(float1 % float2)
print(float1**float2)
String Operations
We can use '+'
operator to concatenate two strings.
# Simple concatenation of two strings
concatenate_string = string1 + string2
print(concatenate_string)
HelloWorld
We can also use f-Strings
method for better formating of string.
In f-Strings
method, we can insert variables in the string format.
# f-Strings method.
f_string = f"Hello World, welcome to the wonderland"
print(f_string)
string1 = "Hello"
string2 = "World"
f_string_var = f"{string1} {string2}, This is testing the f-Strings"
print(f_string_var)
Int
and String
data types, which is not possible.
var_a = "Hello"
var_b = 5
print(var_a + var_b)
# Or this
print(int(var_a) + var_b)
When converting String
to Int
, if the value in that String
is Int
, then we can do addition.
# we could, for example
var_a = "5"
var_b = 5
print(int(var_a) + var_b)
bool1 = True
bool2 = False
# Check if a varible is True
if bool1:
print("bool1 variable is True")
# This print statement is not working
# because bool2 is not True
if bool2:
print("bool2 variable is True")
# Check if a variable is False (not True)
if not bool1:
print("bool1 variable is False")
if not bool2:
print("bool2 variable is False")
# We could use AND, OR operation too.
if bool1 and bool2:
print("Both Variables are True")
if bool1 or bool2:
print("At least one variable is True")
If you want to learn more about data types and their operations in more details, please visit to official Python documentation. You can also learn more about it in this blog post about Basic Data Types in Python.
Data Structures
Python Data Structures are used to store and collect data. There are four basic built-in data structures in Python.
# Simple Creation of each four types of structures
list_obj = [1, 2, 3, 4, 1, 2, 3, 4]
set_obj = {1, 2, 3, 4, 1, 2, 3, 4}
tuple_obj = (1, 2, 3, 4, 1, 2, 3, 4)
dict_obj = {'a':1, 'b':2, 'c':3, 'd':4, 'e':1, 'f':2}
print(type(list_obj), list_obj)
print(type(set_obj), set_obj)
print(type(tuple_obj), tuple_obj)
print(type(dict_obj), dict_obj)
List
The Most commonly used data structure in Python, List
, has the following properties :
- Element are accessable with order
- Mutable (variable values can be changed)
list_height = [170, 172, 174, 160, 178]
print("Heights of student in class...")
print(list_height)
Heights of student in class...
[170, 172, 174, 160, 178]
print("Student A height : ", list_height[0])
print("Student B height : ", list_height[1])
print("Student A height : ", list_height[2])
print("Student B height : ", list_height[3])
print("Student A height : ", list_height[4])
print("Student B height : ", list_height[5])
IndexError: list index out of range.
Because there are only 5 elements in list, list_height[5]
request for 6th element, which is out of range.
num_student = 0
for height in list_height:
num_student += 1
print(height, end = ',')
print(f"\nThere are {num_student} students in the class")
'''
Simple Program:
Convert height information in "cm" to "feet"
'''
# Convert cm to feet
for height_cm in list_height:
height_feet = height_cm * 0.0328 # cm to feet equation
print(f"Studnet height : {height_cm} cm {height_feet:.2f} feet")
student_A = ["Aung Aung", "McE", 3, 6]
student_B = ["Soe Pyae", "Civil", 3, 6]
print("Student A Info : ", student_A)
print("Student B Info : ", student_B)
# But Be Aware, We do not know which element contain what information..
print(student_A[2] + student_A[3])
print(student_A[0] + student_A[1])
print(student_A[1] + student_A[2])
TypeError :can only concatenate str to str | int to int
This often happen in List
when we try to store different data type into one list.
It is hard to get exact index for each element.
For that, in python, we use Dictionary
to store key-value paired information.
# List
student_A_list = ["Aung_Paing", "McE", 3, 6]
student_B_list = ["Soe_Pyae", "Civil", 3, 6]
# Dictionary
student_A_dict = {"Name" : "Aung_Paing",
"Major" : "McE",
"Batch" : 3,
"Year" : 6}
student_B_dict = {"Name" : "Soe_Pyae",
"Major" : "Civil",
"Batch" : 3,
"Year" : 6}
print(student_A_list)
print(student_A_dict)
# If we want to get "Name" info for student_A
name_student_A = student_A[0]
print(name_student_A)
print()
# But in dict, we just need to specified it. We do not need to remember the index of that info.
print("Name : ", student_A_dict["Name"])
print("Major : ", student_A_dict["Major"])
print("Batch : ", student_A_dict["Batch"])
print("Year : ", student_A_dict["Year"])
home_coordinate = (123, 456)
birthday = (11, 1, 1998)
print(type(birthday))
print(birthday)
# Let's try to access the month with index...
month = birthday[1]
print(month)
# Let's try to change the day....
birthday[1] = 10
Thus, we can see the data in tuples cannot be changed
set_obj = {1, 2, 3, 1, 2, 3, 4}
print(type(set_obj))
print(set_obj)
# We cannot access the elements in the set
set_obj[0]
Tips
Error
When you encounter an Error in the code, try the following steps:
- Stay calm & Read the error message carefully
- Copy and paste the error message in google search or stackoverflow.
- Ask for help in forums if necessary.
There are more than 8 million python users in the world and it is very likely that someone has encounterd the same problem as you did. So, don't hesitate to search for help.
We can check the specification of the variable by:
set_obj?
Further Resources for Data Structure
If you would like to know more about Data Structure in Python. Please visit official Python cocumentation. You can also learn more about it in this blog post about Common Python Data Structure
Conditionals
if
Statements in Python allow us to tell the computer to perform alternative actions based on a certain set of results.
In other words, we are telling the computer : "Hey if this case happens, perform some action"
We can then expand the idea further with elif
and else
statements, which allows us to tell the computer: "Hey if this case happens, perform some action. Else, if another case happens, perform some other action. Else, if none of the above cases happened, perform this action"
Let's go ahead and look at the syntax format for if-else
cases to get a better idea of this:
# Simple if-else case
rain = False
if not rain:
print("The weather is fine today, I am going out.")
else:
print("It is raining, I cannot go out...")
# Or this way:
if rain==True:
print("It is raining, I cannot go out...")
else:
print("Today weather is fine, I am going out.")
# sometime, in the program, we have to deal with other conditions
rain = False
weekday = True
if not rain and weekday:
print("I am going to School Today")
elif not rain and not weekday:
print("I am going out to play")
else:
# Rain and weekday
print("Even though it is raining, I still have to go to school ...")
Also, we could check the String
and Int
variables:
if Condition == True
, we use ==
instead of =
# Check String
operation = "add"
if operation == "add":
print("Add Operation")
elif operation == "sub":
print("Sub Operation")
elif operation == "mul":
print("Multiplication Operation")
elif operation == "div":
print("Division Operation")
# Check Int
int_obj = 10
# int_obj = -1 # Comment out to test
# int_obj = 0
# int_obj = None
if int_obj:
print("There exists value for that int_obj")
else:
print("sorry, the input is None or Zero")
A for
loop acts as an iterator in Python; it goes through items that are in a sequence or any other iterable item. Objects, that we've learned and we can iterate over, include strings, lists, tuples, and even built-in iterables for dictionaries, such as keys or values.
Here's the general format for a for loop in Python:
for item in object:
statements to do things
# Loop for 10 times
for i in range(10):
print(i, end=" ")
print()
# Let's access element from list
list_obj = [1, 2, 3, 4, 5, 6, 7, 8, 9]
for obj in list_obj:
print(obj, end=" ")
Tuples
have a special quality when it comes to for
loops. If you are iterating through a sequence that contains tuples, the item can actually be the tuple itself, this is an example of tuple unpacking. During the for
loop we will be unpacking the tuple inside of a sequence and we can access the individual items inside that tuple
.
list1 = [(0,1),(2,3),(4,5)]
for tup in list1:
print(tup)
# Now with unpacking!
for (t1,t2) in list1:
print(t1, end=" ")
In the above case, the first element of each tuple is printed out.
# Now with unpacking!
for (t1,t2) in list1:
print(t2, end=" ")
Here, the second element of each tuple gets printed out.
With tuples in a sequence we can access the items inside of them through unpacking! The reason this is important is because many objects will deliver their iterables through tuples.
nested_list = [[1, 2, 3, 4],
[5, 6, 7, 8]]
# To access nested list, we could use nested for loop
for row in nested_list:
for col in row:
print(col, end=" ")
While
The while
statement in Python is one of most general ways to perform iteration. A while
statement will repeatedly execute a single statement or group of statements as long as the condition is true. The reason it is called a 'loop' is because the code statements are looped through over and over again until the condition is no longer met.
The general format of a while loop is:
while condition:
code statements
else:
final code statements
Let’s look at a few simple while
loops in action.
# While loop and loop for 10 times.
i = 0
while i<10:
print(i, end=" ")
i+=1
x = 0
while x < 5:
print('x is currently:',x)
print('x is still less than 5, keep adding 1 to x')
x += 1
Notice how many times the print statements occurred and how the while
loop kept going until the True condition was met, which occurred once x==5. It's important to note that once this occurred the code stopped. Let's see how we could add an else
statement:
x = 0
while x < 5:
print('x is currently: ',x)
print('x is still less than 5, keep adding 1 to x')
x += 1
else:
print('All Done!')
When the condition isn't true anymore, that is, x is now 5, and so the else statement All Done! is printed out instead.
Further Resources for Conditionals and Loops
If you want to learn more about conditional statements and loops in more details, please visit to official Python documentation. You can also learn more about conditional statements, for loops and while loops in these posts.
int_obj = -5
print(int_obj)
# Find the absolute value
abs_int = abs(int_obj)
print(abs_int)
# Convert Int to String
int2str = str(int_obj)
print(int2str, type(int2str))
# Check the datatype
print(isinstance(int_obj, int))
We can also use built-in functions to construct data-structures.
set_obj = set((1, 2, 3, 1, 2, 3))
print(set_obj)
list_obj = list((1, 2, 3, 1, 2, 3))
print(list_obj)
tuple_obj = tuple((1, 2, 3, 1, 2, 3))
print(tuple_obj)
dict_obj = dict([(1,"a"), (2, "b")])
print(dict_obj)
User-Defined Functions
This section will consist of explaining what a function is in Python and how to create one. Functions will be one of our main building blocks when we construct larger and larger amounts of code to solve problems.
Typical function in python consists of the following parts:
- Input (Arguments in functions)
- Process (What this function do)
- Output (What this function return)
In short, IPO
for constructing a function.
Functions will be one of most basic levels of reusing code in Python, and it will also allow us to start thinking of program design (we will dive much deeper into the ideas of design when we learn about Object Oriented Programming).
def Statements
Let's see how to build out a function's syntax in Python. It has the following form:
def function_name(arg1,arg2):
'''
This is where the function's Document String (docstring) goes
'''
# Do stuff here
# Return desired result
We begin with def then a space, followed by the name of the function. Try to keep names relevant though they can be variable, for example len()
is a good name for a length() function. Also be careful with names, you wouldn't want to call a function the same name as a built-in functions(such as len).
Next comes a pair of parentheses with a number of arguments separated by a comma. These arguments are the inputs for your function. You'll be able to use these inputs in your function and reference them. After this you put a colon.
Now here is the important step, you must indent to begin the code inside your function correctly. Python makes use of whitespace to organize code. Lots of other programing languages do not do this, so keep that in mind.
Let's see the example of creating basic printing function.
# Define a function
# No argument
def print_hello():
print("Hello World")
print_hello() # Call the funtion
Let's see some functions with input arguments.
# Argument with user name
def print_hello(name):
"""
Print The User Name
Args:
name(String) -> User name
Return:
None
"""
print(f"Hello {name}! Welcome.")
print_hello("Aung Aung") # Call the funtion
# Arguments with different datatypes
def print_hello(name, age):
"""
Print The User Name
Args:
name (String) -> User name
age (Int) -> User Age
Return:
None
"""
print(f"Hello {name}! Welcome. You are now {age} years old.")
print_hello("Aung Aung", 22) # Call the funtion
Functions arguments can also have default values. See the example below.
# Argument having default value
def print_hello(name, age = 18):
"""
Print The User Name
Args:
name (String) -> User name
age (Int) -> User Age
Return:
None
"""
print(f"Hello {name}! Welcome. You are now {age} years old.")
# Because the 'age' argument has default value, we don't need to provide value.
print_hello("Aung Aung")
print_hello("Aung Aung", 22)
# Calling the function
add_num(1,2,3)
# Can also save as variable due to return
result = add_num(1,2,3)
print(result)
# Let's try to make a power function
def power(base_num, pow_num):
"""
Calculate the power of base_num
Args:
base_num(Int) -> Base number for calculation
pow_num(Int) -> Power number for calculation
Return:
power_num(Int) -> Power number for calculation
"""
return base_num ** pow_num
# We can directly print out the value
print(power(2, 3))
# Or we can assign the output value to a variable and print.
output = power(3, 2)
print(output)
In the above function:
We get the process of Calculate the Power of base_num
,
Input of base_num
and pow_num
. Output for power_num
.
Further Resources for Functions
If you want to learn more about built-in functions in more details, please visit to official Python documentation. You can also check this blog post about Functions.
Intro to OOP
Let's start the lesson by remembering about the Basic Python Objects. For example:
lst = [0, 1, 2, 3]
When we print out the type of that lst
print(type(lst))
<class 'list'>
This is the built-in Class
of list
.
And we can call methods on that list with
lst.append(2)
lst
[0, 1, 2, 3, 2]
Here, append is the method that the <class 'list'>
has.
print(type(1))
print(type([]))
print(type(()))
print(type({}))
So we know all these things are objects, so how can we create our own Object types? That is where the class
keyword comes in.
Class and Attributes
class
User defined objects are created using the class
keyword. The class is a blueprint that defines the nature of a future object. From classes we can construct instances. An instance is a specific object created from a particular class. For example:
t = (1, 2, 3)
We created the object t which was an instance of a tuple object.
Now, Let's try a step up and create our own class.
# Construct a new object type called Student
class Student:
pass
# Instance of the class Student
x = Student()
print(type(x))
<class '__main__.Student'>
Most of the programmers give classes a name that starts with a capital letter by convention. Note how x is now the instance of a Student class. In other words, we instantiate the Student class.
At the inside of the class we currently just have pass
keyword. But we can define class attributes and methods.
An attribute is a characteristic of an object.
A method is an operation we can perform with the object.
For example, we can create a class called Dog. An attribute of a dog may be its breed or its name, while a method of a dog may be defined by a .bark() method which returns a sound.
Attributes
The syntax for creating an attribute is:
self.attribute = something
There is a special method called:
__init__()
This method is used to initialize the attributes of an object. For example:
class Student:
def __init__(self, name):
self.name = name
a = Student(name = 'Aung Paing')
b = Student(name = 'Soe Pyae Phyo')
Let's break down what we have above. The special method
__init__()
is called automatically right after the object has been created.
def __init__(self, name):
Each attribute in a class definition begins with a reference to the instance object. It is by convention named self. The name is the argument. The value is passed during the class instantiation.
self.name = name
self.name
can be given any desire variable names; no need to be name
. For example, self.student_name = name
a.name
'Aung Aung'
b.name
'Soe Soe'
Note how we don't have any parentheses after name; this is because it is an attribute and doesn't take any arguments.
Lets add more attributes to our Student class.
class Student:
def __init__(self, name, major, batch, age, passedlastterm):
self.name = name
self.major = major
self.batch = batch
self.age = age
self.passedlastterm = passedlastterm
student_a = Student("Myo Myo", "EC", 3, 24, True)
student_b = Student("Su Su", "Text", 2, 18, False)
print("\nStudent a Data :")
print(student_a.name)
print(student_a.major)
print(student_a.batch)
print(student_a.age)
print(student_a.passedlastterm)
Methods
Methods are functions defined inside the body of a class. They are used to perform operations with the attributes of our objects. Methods are a key concept of the OOP pattern. They are essential to dividing responsibilities in programming, especially in large applications.
Let's go through an example of creating a Square class:
class Square:
# Square gets instantiated
def __init__(self, length = 4):
self.length = length
self.area = length * length
# Resetting length
def setLength(self, new_length):
self.length = new_length
self.area = new_length * new_length
s = Square()
print('Length is ', s.length)
print('Area is ', s.area)
s.setLength(6)
print('Now length is ', s.length)
print('Now area is ', s.area)
In this Square class, we have defined two attributes: self.length
and self.area
.
def setLength(self, new_length):
is called method of the class, which we use to interact with the user and manipulate the class attributes. Notice how we used self.
notation to reference attributes of the class within the method calls.
Now, Let's add some methods to Student class.
class Student:
def __init__(self, name, major, batch, age, passedlastterm):
self.name = name
self.major = major
self.batch = batch
self.age = age
self.passedlastterm = passedlastterm
def print_result(self):
if self.passedlastterm:
print("Congrats, you can move to next term.")
else:
print("Sorry, you need to retake the exam.")
student_a = Student("Myo Myo", "EC", 3, 24, True)
print("Student a Result")
student_a.print_result()
Inheritance
Inheritance is a way to form new classes using classes that have already been defined. The newly formed classes are called derived classes, the classes that we derive from are called base classes. Important benefits of inheritance are code reuse and reduction of complexity of a program. The derived classes override or extend the functionality of base classes.
Let's use our Student class again.
# Inheritance and not change anything.
class ExchangeStudent(Student):
pass
In this example, we have two classes: Student and ExchangeStudent. The Student is the base class, the ExchangeStudent is the derived class.
The derived class inherits the functionality of the base class. This is shown in the example below.
# ExchangeStudent should have all properties and methods Student has.
student_ex = ExchangeStudent("Htet Htet", "Civil", 1, 25, True)
print("\nStudent ex Result")
student_ex.print_result()
Student ex Result
Congrats, you can move to next term.
Further Resources for Class
If you want to learn more about Object Oriented Programming (OOP) in more details, please visit to official Python documentation. You can also check this blog post about OOP.