Nothing Special   »   [go: up one dir, main page]

Midterm Python

Download as doc, pdf, or txt
Download as doc, pdf, or txt
You are on page 1of 70
At a glance
Powered by AI
The document discusses topics related to object-oriented programming in Python including classes, inheritance, polymorphism, modules, packages, errors, exceptions, decorators, generators and iterators.

The document covers topics like object-oriented programming fundamentals, classes, inheritance, polymorphism, modules, packages, errors and exceptions handling, decorators, generators and iterators in Python.

The main principles of object-oriented programming discussed are encapsulation, data abstraction, polymorphism and inheritance.

OBJECT ORIENTED

PROGRAMMING 1

Felix L. Huerte Jr.


Table of Contents

Module 5: Object Oriented Programming 125


Introduction 125

Learning Objectives 125


Lesson 1. Object Oriented Programming Fundamentals 126
Lesson 2. Class Object, Attributes and Methods 128
Lesson 3. Inheritance 137
Lesson 4. Polymorphism 142
Lesson 5. Special Methods 143
MODULE 6: Modules, Packages, Errors and Exceptions Handling 151

Introduction 151

Learning Objectives 151


Lesson 1. Modules and Packages 158
Lesson 2. Errors and Exceptions Handling 161

MODULE 7: Python Decorators and Generators 177


Introduction 177

Learning Objectives 177


Lesson 1. Decorators 178
Lesson 2. Iterators and Generators 184

124
MODULE 5
Object Oriented Programming

Introduction

This Module deals with Object Oriented Programming or OOP. Although Python can be
used without programming in an OOP style as preferred by most of the beginners and if they only
want to write small to middle-sized application this is good enough. But for larger applications
and projects it is recommended to get into OOP. In as much that OOP is needed, almost every
aspects of Python OOP was provided in the following lessons (Klein, 2020).

For much larger scripts of Python code, functions by themselves are not enough for organization
and repeatability. Commonly repeated tasks and objects can be defined with OOP to create code
that is more usable (Klein, 2020).

You will learn to know the four major principles of object-orientation and the way
Python deals with them on object-oriented programming, they are:

• Encapsulation
• Data Abstraction
• Polymorphism
• Inheritance

OOP allows users to create their own objects. The general format is often confusing when
first encountered, and its usefulness may not be completely clear at first.

In general, OOP allows us to create code that is repeatable and organized. Object Oriented
Programming (OOP) allows programmers to create their own objects that have methods and
attributes. Recall that in the previous modules we learned that after defining a string, list,
dictionary, or other objects, you were able to call methods with method_name() syntax. We also
learned that these methods act as functions that use

125
information about the object, as well as the object itself to return results, or change the
current object.

Learning Outcomes

At the end of this module, students should be able to:

1. Describe and explain Object-Oriented Programming;

2. Define a class, which is a sort of blueprint for an object;

3. Instantiate an object from class

4. Use and apply attributes and methods to define the properties and
behaviors of an object;

5. Design and demonstrate OOP principles;

6. Put into practice Python language as related to OOP;

7. Construct and manage OOP programming structure independently.

Lesson 1. Object Oriented Programming Fundamentals

According to Klein (2020), everything is a class in Python. Guido van Rossum has
designed the language according to the principle "first-class everything". He wrote: "One
of my goals for Python was to make it so that all objects were "first class." By this, I
meant that I wanted all objects that could be named in the language (e.g., integers, strings,
functions, classes, modules, methods, and so on) to have equal status. That is, they can be
assigned to variables, placed in lists, stored in dictionaries, passed as arguments, and so
forth." (Blog, The History of Python, February 27, 2009) In other words, "everything" is
treated the same way, everything is a class: functions and methods are values just like lists,
integers or floats. Each of these are instances of their corresponding classes

126
Object Oriented Programming (OOP) tends to be one of the major obstacles for
beginners when they are first starting to learn Python. As beginners please feel free to
Google and search lessons about OOP for more information and understanding (Klein,
2020).

For this lesson we will construct, create and develop more knowledge of OOP in
Python by presenting and discuss on the following topics:

• Objects
• Using the class keyword
• Creating class attributes
• Creating methods in a class
• Learning about Inheritance
• Learning about Polymorphism
• Learning about Special Methods for classes

Overview of OOP Terminology (tutorialspoint, 2016)

• Class − A user-defined prototype for an object that defines a set of attributes that
characterize any object of the class. The attributes are data members (class
variables and instance variables) and methods, accessed via dot notation.

• Class variable − A variable that is shared by all instances of a class. Class variables
are defined within a class but outside any of the class's methods. Class variables are
not used as frequently as instance variables are.

• Data member − A class variable or instance variable that holds data associated
with a class and its objects.

• Function overloading − The assignment of more than one behavior to a particular


function. The operation performed varies by the types of objects or arguments
involved.

• Instance variable − A variable that is defined inside a method and belongs only to
the current instance of a class.

• Inheritance − The transfer of the characteristics of a class to other classes that are
derived from it.

127
• Instance − An individual object of a certain class. An object obj that belongs to a
class Circle, for example, is an instance of the class Circle.
• Instantiation − The creation of an instance of a class.
• Method − A special kind of function that is defined in a class definition.
• Object − A unique instance of a data structure that's defined by its class.

An object comprises both data members (class variables and instance variables)
and methods.

• Operator overloading − The assignment of more than one function to a particular


operator.

Let us start the lesson by remembering about the Basic Python Objects. For example:

Remember how we could call methods on a list?

We've already learned about how to create functions. So let's explore Objects in general:

Lesson 2. Class Object, Attributes and Methods


(Pierian Data, Udemy, n.d.).

Objects

In Python, everything is an object. Remember from previous lectures we can use type()
to check the type of object something is:

128
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, above we created the object lst which was an
instance of a list object (Pierian Data, Udemy, n.d.). Let see how we can use class (Pierian Data,
Udemy, n.d.):

By convention we give classes a name that starts with a capital letter. Note how x is now the
reference to our new instance of a Sample class. In other words, we instantiate the Sample class.

Inside of the class we currently just have pass. 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.

129
Let's get a better understanding of attributes through an example.

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:

Lets break down what we have above. The special method

__init__() is called automatically right after the object has been created:

def __init__(self, breed):

Each attribute in a class definition begins with a reference to the instance object. It is by
convention named self. The breed is the argument. The value is passed during the class
instantiation.

self.breed = breed

Now we have created two instances of the Dog class. With two breed types, we can then access
these attributes like this:

130
Note how we don't have any parentheses after breed; this is because it is an attribute and
doesn't take any arguments.

In Python there are also class object attributes. These Class Object Attributes are the same for
any instance of the class. For example, we could create the attribute species for the Dog class.
Dogs, regardless of their breed, name, or other attributes, will always be mammals. We apply
this logic in the following manner (Pierian Data, Udemy, n.d.):

Note that the Class Object Attribute is defined outside of any methods in the class.
Also by convention, we place them first before the init.

Methods (Pierian Data, Udemy, n.d.).

As we have taken from the previous module, 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 paradigm. They are essential to dividing responsibilities in
programming, especially in large applications.

You can basically think of methods as functions acting on an Object that take the Object
itself into account through its self-argument.

131
Let's go through an example of creating a Circle class:

In the _init_ method above, in order to calculate the area attribute, we had to call
Circle.pi. This is because the object does not yet have its own .pi attribute, so we call the
Class Object Attribute pi instead (Pierian Data, Udemy, n.d.).

In the setRadius method, however, we will be working with an existing Circle object that
does have its own pi attribute. Here we can use either Circle.pi or self.pi.

Now let's change the radius and see how that affects our Circle object:

132
Notice how we used self. notation to reference attributes of the class within the method calls.
Review how the code above works and try creating your own method.

As illustrated by Programiz, (2019), One of the popular approaches to solve a


programming problem is by creating objects. This is known as Object-Oriented
Programming (OOP)(

An object has two characteristics:

• attributes
• behavior

Let's take an example:

A parrot can be an object, as it has the following properties:

• name, age, color as attributes


• singing, dancing as behavior

The concept of OOP in Python focuses on creating reusable code. This concept is also
known as DRY (Don't Repeat Yourself).

In Python, the concept of OOP follows some basic principles:

Class
A class is a blueprint for the object.

We can think of class as a sketch of a parrot with labels. It contains all the details about
the name, colors, size etc. Based on these descriptions, we can study about the parrot.

Here, a parrot is an object (Pierian Data, Udemy, n.d.).

The example for class of parrot can be :

class Parrot:
pass

133
Here, we use the class keyword to define an empty class Parrot. From class, we construct
instances. An instance is a specific object created from a particular class.

Object

An object (instance) is an instantiation of a class. When class is defined, only the description
for the object is defined. Therefore, no memory or storage is allocated.

The example for object of parrot class can be:

obj = Parrot()

Here, obj is an object of class Parrot.

Suppose we have details of parrots. Now, we are going to show how to build the class and
objects of parrots.

Example 1: Creating Class and Object in Python

class Parrot:

# class attribute
species = "bird"

# instance attribute def


__init__(self, name, age):
self.name = name
self.age = age

# instantiate the Parrot class


blu = Parrot("Blu", 10) woo =
Parrot("Woo", 15)

# access the class attributes

134
print("Blu is a {}".format(blu.__class__.species)) print("Woo is also a
{}".format(woo.__class__.species))

# access the instance attributes

print("{} is {} years old".format( blu.name, blu.age)) print("{} is {}


years old".format( woo.name, woo.age))
Output

Blu is a bird
Woo is also a bird
Blu is 10 years old
Woo is 15 years old

In the above program, we created a class with the name Parrot. Then, we define attributes.
The attributes are a characteristic of an object.

These attributes are defined inside the __init__ method of the class. It is the initializer
method that is first run as soon as the object is created.

Then, we create instances of the Parrot class. Here, blu and woo are references (value) to
our new objects.

We can access the class attribute using __class__.species. Class attributes are the same for
all instances of a class. Similarly, we access the instance attributes using blu.name and
blu.age. However, instance attributes are different for every instance of a class.

Python Classes and Objects (w3schools, 2018)

Almost everything in Python is an object, with its properties and methods.

A Class is like an object constructor, or a "blueprint" for creating objects.

135
Create a Class (w3schools, 2018)

To create a class, use the keyword class:

Example:

Create a class named MyClass, with a property named x:

class MyClass:
x=5
Create Object (w3schools, 2018)

Now we can use the class named MyClass to create objects:

Example

Create an object named p1, and print the value of x:

p1 = MyClass()
print(p1.x)

The __init__() Function

The examples above are classes and objects in their simplest form, and are not really
useful in real life applications.

To understand the meaning of classes we have to understand the built-in __init__()


function.

All classes have a function called __init__(), which is always executed when the class is
being initiated.

Use the __init__() function to assign values to object properties, or other operations that
are necessary to do when the object is being created:

136
Example

Create a class named Person, use the __init__() function to assign values for name and
age:

class Person:

def __init__(self, name, age):


self.name = name
self.age = age

p1 = Person("John", 36)

print(p1.name)
print(p1.age)

Note: The function is called automatically every time the class is being
__init__()

used to create a new object.

Lesson 3. Inheritance (Pierian Data, Udemy, n.d.)

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 derived from are
called base classes. Important benefits of inheritance are code reuse and reduction of

complexity of a program. The derived classes (descendants) override or extend the


functionality of base classes (ancestors).

Let's see an example by incorporating our previous work on the Dog class:

137
In this example, we have two classes: Animal and Dog. The Animal is the base class, the
Dog is the derived class (Pierian Data, Udemy, n.d.).

The derived class inherits the functionality of the base class.

• It is shown by the eat() method.

The derived class modifies existing behavior of the base class.

• shown by the whoAmI() method.

138
Finally, the derived class extends the functionality of the base class, by defining a new
bark() method.

Based from Programiz (2014), Inheritance enables us to define a class that takes
all the functionality from a parent class and allows us to add more. In this tutorial, you
will learn to use inheritance in Python.

Inheritance is a powerful feature in object oriented programming. It refers to


defining a new class with little or no modification to an existing class. The also single out
that the new class is called derived (or child) class and the one from which it inherits is
called the base (or parent) class (Programiz, 2014).

Python Inheritance Syntax

class BaseClass: Body of


base class class
DerivedClass(BaseClass):
Body of derived class

Derived class inherits features from the base class where new features can be added to it.

This results in re-usability of code.

Example of Inheritance in Python (Programiz (2020)

To demonstrate the use of inheritance, let us take an example.

A polygon is a closed figure with 3 or more sides. Say, we have a class called

Polygon defined as follows.

139
class Polygon: def
__init__(self, no_of_sides):
self.n = no_of_sides
self.sides = [0 for i in range(no_of_sides)]

def inputSides(self):
self.sides = [float(input("Enter side "+str(i+1)+" : ")) for i in range(self.n)]

def dispSides(self):
for i in range(self.n):
print("Side",i+1,"is",self.sides[i])

This class has data attributes to store the number of sides and magnitude of each side

as a list called sides .

140
141
t.dispSides()

Side 1 is 3.0
Side 2 is 5.0
Side 3 is 4.0

t.findArea()

The area of the triangle is 6.00

e can see that even though we did not define methods like dispSides() for
inputSides() or

class Triangle separately, we were able to use them.

If an attribute is not found in the class itself, the search continues to the base class.
This repeats recursively, if the base class is itself derived from other classes.

Lesson 4. Polymorphism (Pierian Data, Udemy, n.d.)

Polymorphism

We've learned that while functions can take in different arguments, methods belong to the
objects they act on. In Python, polymorphism refers to the way in which different object
classes can share the same method name, and those methods can be called from the same
place even though a variety of different objects might be passed in. The best way to
explain this is by example

142
Here we have a Dog class and a Cat class, and each has a .speak() method. When called,
each object's .speak() method returns a result unique to the object.

There a few different ways to demonstrate polymorphism. First, with a for loop:

143
In both cases we were able to pass in different object types, and we obtained object specific
results from the same mechanism.

A more common practice is to use abstract classes and inheritance. An abstract class is one that
never expects to be instantiated. For example, we will never have an Animal object, only Dog and
Cat objects, although Dogs and Cats are derived from Animals:

Real life examples of polymorphism include:

• opening different file types - different tools are needed to display Word, pdf and
Excel files

• adding different objects - the + operator performs arithmetic and concatenation

Polymorphism (Programiz, 2019)

144
Polymorphism is an ability (in OOP) to use a common interface for multiple forms (data
types).

Suppose, we need to color a shape, there are multiple shape options (rectangle, square,
circle). However, we could use the same method to color any shape. This concept is
called Polymorphism.

Example

145
Lesson 5. Special Methods (Pierian Data, Udemy, n.d.)

Finally let's go over special methods. Classes in Python can implement certain operations with
special method names. These methods are not actually called directly but by Python specific
language syntax. For example, let us create a Book class:

The __init__(), __str__(), __len__() and __del__() methods

These special methods are defined by their use of underscores. They allow us to use Python
specific functions on objects created through our class (Pierian Data, Udemy, n.d.).

For more great resources on this topic, check out:

Jeff Knupp's Post

Mozilla's Post

Tutorial's Point

Official Documentation

146
Summary

From this module lecture you should have learned the basic understanding of how
to create your own objects with class in Python. Class attributes were also introduced to you as an
important element of class and object. We also introduced methods where the actions taking place
in classes and objects are performed and done. Classes in Python can implement certain
operations with special method names. These methods are not actually called directly but by
Python specific language syntax.

Inheritance was explained together with polymorphism. We learned that Inheritance enables
us to define a class that takes all the functionality from a parent class and allows us to add more.
Polymorphism on the other hand, refers to the way in which different object classes can share the same
method name, and those methods can be called from the same place even though a variety of different
objects might be passed in.

147
Assessment Task 5-1

Work from Home Assignment

Problem 1

Illustrated below is a program skeletal form of class UpaSaWork.Fill in the class


methods to acceptdata needed intuples format and return theNetpay of the
employee wiyh his/her name as part of the final output.

148
Problem 2

Fill in the Barrel class methods to acceptthe taas and diaHalf of the barrelthen
return the kabuuangSukat and sukatNgLawak of the barrel.

149
References

Programiz (2020) Python Object Oriented Programming.


https://www.programiz.com/python-programming/object-
orientedprogramming

Python Course (2020) ython Tutorial: Object Oriented Programming.


https://www.pythoncourse.eu/python3_object_oriented_programming.php

Tutorialspoint (2020) Python 3 - Object Oriented


https://www.tutorialspoint.com/python3/python_classes_objects.htm

Udemy. (n.d.). GitHub - Pierian-Data/Complete-Python-3-Bootcamp: Course


Files fR Complete Python 3 Bootcamp Course https://github.com/Pierian-
Data/Complete-Python-3-Bootcamp

W3School (2018) Python Classes.


https://www.w3schools.com/python/python_classes.asp

150
MODULE 6
Modules, Packages, Errors and Exceptions
Handling

Introduction

This module will explore Python modules and packages. These are the mechanisms that
make modular programming easier.

Another structure of Python Object Oriented Programming is Modular


programming which refers to the process of dividing or breaking a large programming
task into separate, smaller, more manageable subtasks or modules. Individual modules can
then be put together like puzzle or building blocks to create a larger application.

In programming, a module is a piece of software that has a specific functionality.


Each module is a different file, which can be edited separately.

This module will provide the different side as compared to functional


programming structure. Python modules are imported and use directly yet they are easy to
create and use by you.

Modules can be used repeatedly so as to lessen or eliminate repetitions of writing


the same code. Remember the acronym “DRY” which means “Don’t Repeat Yourself”.
We can BRY up our code by taking identical sections of code and using them many
times. Applying modules make it easier to understand, manage and maintain our code.

Error and exemption handling will also be introduced in this section. We will learn
that errors can be detected and can be trapped with error handling structure so as to continue
the program execution without a halt. By using the try, except,

151
else and finally as the structure we want to use can help programmer to maintain integrity
of the program executions.

Learning Outcomes

At the end of this module, students should be able to:

1. Discuss and describe the Python packages and modules;

2. Design and write packages and modules;

3. Apply and demonstrate error trapping and the application of handling them;

4. Compare Python data types and its structure with other programming languages;

5. Interpret and evaluate how and why package, module are apply in modular programming.

Lesson 1. Modules and Packages

To start with, we should know that there are various and different advantages to
modularizing code in a large application (Sturtz, 2018):

• Simplicity: Rather than focusing on the entire problem at hand, a module


typically focuses on one relatively small portion of the problem. If you’re
working on a single module, you’ll have a smaller problem domain to wrap your
head around. This makes development easier and less error-prone.

• Maintainability: Modules are typically designed so that they enforce logical


boundaries between different problem domains. If modules are written in a way
that minimizes interdependency, there is decreased likelihood that modifications
to a single module will have an impact on other parts of the program. (You may
even be able to make changes to a module without having any knowledge of the
application outside that module.) This makes it more viable for a team of many
programmers to work collaboratively on a large application.

152
• Reusability: Functionality defined in a single module can be easily reused
(through an appropriately defined interface) by other parts of the application.
This eliminates the need to duplicate code.

• Scoping: Modules typically define a separate namespace, which helps avoid


collisions between identifiers in different areas of a program. (One of the tenets in
the Zen of Python is Namespaces are one honking great idea—let’s do more of
those!)

Python Modules (javatpoint, 2014)

A python module, according to javatpoint, (2014) can be defined as a python program file
which contains a python code including python functions, class, or variables. In other
words, we can say that our python code file saved with the extension (.py) is treated as the
module. We may have a runnable code inside the python module.

Modules in Python provides us the flexibility to organize the code in a logical way.

To use the functionality of one module into another, we must have to import the specific
module.

Example

In this example, we will create a module named as file1.py which contains a function func
that contains a code to print some message on the console.

Let's create the module named as file1.py.

#displayMsg prints a message to the name being passed.


def displayMsg(name)
print("Hi "+name)

Here, we need to include this module into our main module to call the method
displayMsg() defined in the module named file.

153
Loading the module in our python code (javatpoint, 2014)

We need to load the module in our python code to use its functionality. Python provides
two types of statements as defined below.

1. The import statement

2. The from-import statement

The import statement (javatpoint, 2014)

The import statement is used to import all the functionality of one module into another.
Here, we must notice that we can use the functionality of any python source file by
importing that file as the module into another python source file.

We can import multiple modules with a single import statement, but a module is loaded
once regardless of the number of times, it has been imported into our file.

The syntax to use the import statement is given below.

import module1, module2,........ module n

Now, create a new class and If we need to call the function displayMsg() defined in the
file file1.py, we have to import that file as a module into our module as shown in the
example below.

Example: (name file as file2.py)


import file1
name = input("Enter the name?")
file.displayMsg(name)

154
Output:

Enter the name?John


Hi John

The from - import statement

Instead of importing the whole module into the namespace, python provides the flexibility
to import only the specific attributes of a module. This can be done by using from - import
statement. The syntax to use the from-import statement is given below. from < module-
name> import <name 1>, <name 2>..,<name n>

Consider the following module named as calculation which contains three functions as
summation, multiplication, and divide.

calculation.py:

#place the code in the


calculation.py def
summation(a,b):
return a+b

def multiplication(a,b):
return a*b;

def divide(a,b):
return a/b;

Main.py:

from calculation import summation


#it will import only the summation() from
calculation.py a = int(input("Enter the first
number")) b = int(input("Enter the second
number")) print("Sum = ",summation(a,b))

155
Output:

Enter the first number10


Enter the second number20
Sum = 30

The from...import statement is always better to use if we know the attributes to be imported
from the module in advance. However, we can also import all the attributes from a module by
using * but will use greater memory (javatpoint, 2014).

Consider the following syntax.

from <module> import *


Renaming a module

Python provides us the flexibility to import some module with a specific name so that we
can use this name to use that module in our python source file.

The syntax to rename a module is given below.

import <module-name> as <specific-name>

Example

#the module calculation of previous example is imported in this example as cal. import
calculation as cal;
a = int(input("Enter a?"));
b = int(input("Enter b?"));
print("Sum =
",cal.summation(a,b))

Output:

Enter a?10
Enter b?20
Sum = 30

156
Using dir() function

The dir() function returns a sorted list of names defined in the passed module. This list
contains all the sub-modules, variables and functions defined in this module.

Consider the following example.

Example
import json

List = dir(json)

print(List)
Output:

['JSONDecoder', 'JSONEncoder', '__all__', '__author__', '__builtins__',


'__cached__', '__doc__',

'__file__', '__loader__', '__name__', '__package__', '__path__', '__spec__',


'__version__',

'_default_decoder', '_default_encoder', 'decoder', 'dump', 'dumps', 'encoder', 'load',


'loads', 'scanner']

The reload() function

As we have already stated that, a module is loaded once regardless of the number of times
it is imported into the python source file. However, if you want to reload the already
imported module to re-execute the top-level code, python provides us the reload()
function. The syntax to use the reload() function is given below (javatpoint, 2014).
reload(<module-name>)

for example, to reload the module calculation defined in the previous example, we must
use the following line of code.

reload(calculation)

157
Scope of variables

In Python, variables are associated with two types of scopes. All the variables defined in a
module contain the global scope unless or until it is defined within a function (javatpoint,
2014).

All the variables defined inside a function contain a local scope that is limited to this
function itself. We can not access a local variable globally (javatpoint, 2014).

If two variables are defined with the same name with the two different scopes, i.e., local
and global, then the priority will always be given to the local variable (javatpoint, 2014).

Consider the following example.


Example name = "john" def print_name(name): print("Hi",name)
#prints the name that is local to this function only.

name = input("Enter the name?")


print_name(name)

Output:

Hi David

More on Modules and Packages (Udemy, n.d.)

To begin with, please check out the video lectures for more info and the resources for
this.

Here is the best source the official docs!


https://docs.python.org/3/tutorial/modules.html#packages

But I really like the info here:


https://python4astronomers.github.io/installation/packages.html

Here's some extra info to help:

158
Modules in Python are simply Python files with the .py extension, which implement a set
of functions. Modules are imported from other modules using the import command.

To import a module, we use the import command. Check out the full list of built-in
modules in the Python standard library in this site: https://docs.python.org/3/py-
modindex.html.

The first time a module is loaded into a running Python script, it is initialized by executing the
code in the module once. If another module in your code imports the same module again, it
will not be loaded twice but once only - so local variables inside the module act as a
"singleton" - they are initialized only once (Udemy, n.d.).

If we want to import the math module, we simply import the name of the module
(Udemy, n.d.):

Exploring built-in modules

Two very important functions come in handy when exploring modules in Python - the dir
and help functions (Udemy, n.d.).

We can look for which functions are implemented in each module by using the dir
function:

159
When we find the function in the module we want to use, we can read about it more using
the help function, inside the Python interpreter:

Writing modules

Writing Python modules is very simple. To create a module of your own, simply create a
new .py file with the module name, and then import it using the Python file name (without
the .py extension) using the import command (Udemy, n.d.).
Writing packages

Packages are name-spaces which contain multiple packages and modules themselves.
They are simply directories, but with a twist (Udemy, n.d.).

Each package in Python is a directory which MUST contain a special file called
_init_.py. This file can be empty, and it indicates that the directory it contains is a
Python package, so it can be imported the same way a module can be imported (Udemy,
n.d.).

If we create a directory called foo, which marks the package name, we can then create a
module inside that package called bar. We also must not forget to add the _init_.py file
inside the foo directory.

To use the module bar, we can import it in two ways:

160
In the first method, we must use the foo prefix whenever we access the module bar. In
the second method, we don't, because we import the module to our module's
namespace.

The _init_.py file can also decide which modules the package exports as the API, while
keeping other modules internal, by overriding the _all_ variable, like so:

Lesson 2. Errors and Exceptions Handling


Errors and Exception Handling (Udemy, n.d.)

In this lecture we will learn about Errors and Exception Handling in Python. You've definitely
already encountered errors by this point in the course. For example:

Note how we get a Syntax Error, with the further description that it was an EOL (End of
Line Error) while scanning the string literal. This is specific enough for us to see that we
forgot a single quote at the end of the line. Understanding these various error types will
help you debug your code much faster (Udemy, n.d.).

This type of error and description is known as an Exception. Even if a statement or expression
is syntactically correct, it may cause an error when an attempt is made

161
to execute it. Errors detected during execution are called exceptions and are not
unconditionally fatal (Udemy, n.d.).

You can check out the full list of built-in exceptions at this page:
https://docs.python.org/3/library/exceptions.html.

Now let's learn how to handle errors and exceptions in our own code.

The try and except statements

The basic terminology and syntax used to handle errors in Python are the try and except
statements. The code which can cause an exception to occur is put in the try block and the
handling of the exception is then implemented in the except block of code (Udemy,n.d.).
The syntax follows:

try:

You do your operations here...

...

except ExceptionI:

If there is ExceptionI, then execute this block. except ExceptionII:

If there is ExceptionII, then execute this block.

...

else:

If there is no exception then execute this block.

We can also just check for any exception with just using except: To get a better
understanding of all this let's check out an example: We will look at some code that opens
and writes a file (Udemy,n.d.):

162
Now let's see what would happen if we did not have write permission (opening only with
'r'):

Notice how we only printed a statement! The code still ran and we were able to continue
doing actions and running code blocks. This is extremely useful when you have to account
for possible input errors in your code. You can be prepared for the error and keep running
code, instead of your code just breaking as we saw above (Udemy,n.d.).
We could have also just said except: if we are not sure what exception would occur.
For example:

163
Now we don't actually need to memorize that list of exception types! Now what if we
kept wanting to run code after the exception occurred? This is where finally comes in
(Udemy,n.d.).

Finally statement

The finally: block of code will always be run regardless if there was an
exception in the try code block. The syntax is (Udemy,n.d.):

try:

Code block here

...

Due to any exception, this code may be skipped!

finally:

This code block would always be executed.

164
For example:

Notice how we got an error when trying to print val (because it was never properly
assigned). Let's remedy this by asking the user and checking to make sure the input type
is an integer:

165
That only did one check. How can we continually keep checking? We can use a while
loop!

166
So why did our function print "Finally, I executed!" after each trial, yet it never printed
val itself? This is because with a try / except / finally clause, any continue or break
statements are reserved until after the try clause is completed. This means that even
though a successful input of 3 brought us to the else: block, and a break statement was
thrown, the try clause continued through to finally: before breaking out of the while loop.
And since print(val) was outside the try clause, the break statement prevented it from
running (Udemy,n.d.). Let's make one final adjustment:

167
Now you know how to handle errors and exceptions in Python with the try, except, else, and
finally notation!

More on Python Exception Handling Using try, except and


finally statements (Programiz, 2014)

In this lesson, you'll learn how to handle exceptions in your Python program using try, except
and finally statements with the help of examples.

Exceptions in Python

Python has many built-in exceptions that are raised when your program encounters an
error (something in the program goes wrong).

When these exceptions occur, the Python interpreter stops the current process and passes
it to the calling process until it is handled. If not handled, the program will crash.

168
For example, let us consider a program where we have a function which in turn calls
function C. If an exception occurs in function C the exception passes to B and then to A.
If never handled, an error message is displayed and our program comes to a sudden
unexpected halt (Programiz, 2014).

Catching Exceptions in Python

In Python, exceptions can be handled using a try statement. can raise an exception is placed
inside the try exceptions is written in the except clause (Programiz, 2014).

We can thus choose what operations to perform once we have caught the exception. Here
is a simple example. A that calls function but is not handled in The critical operation
which clause. The code that handles the B,

Catching Specific Exceptions in Python

In the above example, we did not mention any specific exception in the except clause.
This is not a good programming practice as it will catch all exceptions and handle every
case in the same way. We can specify except which exceptions an except clause should
catch. A try clause can have any number of clauses to handle different exceptions,
however, only one will be executed in case an exception occurs (Programiz, 2014). We
can use a tuple of values to specify multiple exceptions in an except clause. Here is an
example pseudo code (Programiz, 2014).

169
170
> raise KeyboardInterrupt Traceback
(most recent call last):

...

KeyboardInterrupt

> raise MemoryError("This is an argument")


Traceback (most recent call last):

...

MemoryError: This is an argument

> try:

... a = int(input("Enter a positive integer: "))

... if a <= 0:

... raise ValueError("That is not a positive number!")

... except ValueError as ve: ...

print(ve) ...

Enter a positive integer: -2

That is not a positive number!

Python try with else clause

In some situations, you might want to run a certain block of code if the code block inside try ran
without any errors. For these cases, you can use the optional else keyword with the try statement
(Programiz, 2014).

Note: Exceptions in the else clause are not handled by the preceding except clauses.
Let's look at an example:

171
# program to print the reciprocal of even numbers
try:

num = int(input("Enter a number: "))

assert num % 2 == 0 except:

print("Not an even number!") else:

reciprocal = 1/num

print(reciprocal)

Output

If we pass an odd number:

Enter a number: 1

Not an even number!

If we pass an even number, the reciprocal is computed and displayed.

172
Here is an example of file operations to illustrate this.

try:

f = open("test.txt",encoding = 'utf-8')

# perform file operations finally:


f.close()

This type of construct makes sure that the file is closed even if an exception occurs during the
program execution.

Summary

Through this module, we have learned that Packages and Modules are used
program. We also learned that packages are collections of modules that you create and

use. We import modules in the directory use to run the program directly, but to import
modules from other directories, we have to let Python know that the directory we are

importing from is a Python package.

Furthermore, we have to consider that modular programming as referred, is the


process of breaking a large programming task into separate, smaller, more manageable
subtasks or modules that they can then be group together as blocks to create a larger
application.

This module also has introduced Errors and Exemption Handling. We have

learned that errors can be detected and can be trapped with error handling structure so as

to continue the program execution. By using the try, except, else and finally as the

structure we want to use can help programmer to maintain integrity of the program

executions. It is advised therefore that Python error and exemption handling be used and

applied as part of program code structure.

173
Assessment Task 6.1

Test your knowledge.


Problem 1.

With Pycharm IDE, write a simple module file – a file containing a single statement:
print(“Hello, This is my Module”). Store this statement in a file named
moduleFile.py. Create another .py program name as Main.py to communicate with the
other program to display the output therein.

Problem 2

Using try and except blocks , address the exception thrown by the code below.

174
Problem 3

Using try and excep t blocks, resolve the exception thrown by the code
I Got It block.
below, then print “ ” by using the finally

Problem 4
Using a while loop with a try, excep t, else block to check for an incorrect inputs.
Furthermore, w rite a function that asks for an integer and display the square root of it.

175
References

Programiz, (2014) Python Exception Handling Using try, except and finally
statement. (2020). Retrieved 15 September 2020, from
https://www.programiz.com/pythonprogramming/exception-handling

Udemy, (n.d) Complete-Python-3-Bootcamp-master/Complete-Python-3-


Bootcampmaster/07

176
MODULE 7

Python Decorators and Generators

Introduction
In this module, we will learn Python decorators and Generators.

In Python decorators, you will learn what they are, how they are created
and how they are use. Decorators provide a simple syntax for calling higher-order
functions in Python. As defined, a decorator is a function that takes another function and
extends the behavior of the called function or the second function without literally
modifying it.

Generators allow us to generate as we go along, instead of holding everything in memory.


We use function in creating a python generator. A generator in python makes use of the
‘yield’ keyword. A Python generator saves the states of the local variables every time
‘yield’ pauses the loop. A generator may have any number of ‘yield’ statements. To add, a
generator does not need a class in python.

Learning Outcomes
At the end of this module, students should be able to:

1. Understand how decorators and generators are designed, created and implemented in a program

2. Write generators and decorators and apply their functionality

3. Evaluate how decorators and generators functionality

4. Analyze the difference in between decorators and generators

177
Lesson 1. Decorators (Udemy, n.d.)

Decorators can be thought of as functions which modify the functionality of another


function. They help to make your code shorter and more "Pythonic".

To properly explain decorators, we will slowly build up from functions. Make sure to run
every cell in this Notebook for this lecture to look the same on your own computer.

So let's break down the steps:

Functions Review (Udemy, n.d.)

Scope Review

Remember from the nested statements lecture that Python uses Scope to know what a
label is referring to (Udemy, n.d.). For example:

Remember that Python functions create a new scope, meaning the function has its own
namespace to find variable names when they are mentioned within the function (Udemy,
n.d.). We can check for local variables and global variables with the locals() and globals()
functions.

For example:

Here we get back a dictionary of all the global variables, many of them are predefined in
Python. So let's go ahead and look at the keys:

178
Note how s is there, the Global Variable we defined as a string

Now let us run our function to check for local variables that might exist inside our
function
(there shouldn't be any)

Now let us continue with building out the logic of what a decorator is. Remember that in
Python everything is an object. That means functions are objects which can be assigned
labels and passed into other functions. Let’s start with some simple examples:

Assign another label to the function. Note that we are not using parentheses here because
we are not calling the function hello, instead we are just passing a function object to the
greet variable (Udemy, n.d.).

Now, what happens when we delete the name hello?

179
Even though we deleted the name hello, the name greet still points to our original
function object. It is important to know that functions are objects that can be passed to
other objects!

Functions within functions

We have seen how we can treat functions as objects, now let's see how we can define
functions inside of other functions (Udemy, n.d.):

180
Note how due to scope, the welcome() function is not defined outside of the hello()
function. Now let us learn about returning functions from within functions (Udemy, n.d.):

Returning Functions

Now let's see what function is returned if we set x = hello(), note how the empty
parentheses means that name has been defined as Jose.

Great! Now we can see how x is pointing to the greet function inside of the hello function.

Let's take a quick look at the code again.

181
In the if/else clause we are returning “greet” and “welcome”, not greet() and welcome().

This is because when you put a pair of parentheses after it, the function gets executed; whereas
if you don’t put parentheses after it, then it can be passed around and can be assigned to other
variables without executing it.

When we write x = hello(), hello() gets executed and because the name is Jose by default, the
function greet is returned. If we change the statement to x = hello(name = "Sam") then the
welcome function will be returned. We can also do print(hello()()) which outputs “This is inside
the greet() function.”

Functions as Arguments

Now let's see how we can pass functions as arguments into other functions (Udemy, n.d.):

Note how we can pass the functions as objects and then use them within other functions.
Now we can get started with writing our first decorator:

Creating a Decorator

In the previous example we actually manually created a Decorator. Here we will modify it
to make its use case clear (Udemy, n.d.):

182
So what just happened here? A decorator simply wrapped the function and modified its
behavior. Now let's understand how we can rewrite this code using the @ symbol, which
is what Python uses for Decorators:

You've now built a Decorator manually and then saw how we can use the @ symbol in
Python to automate this and clean our code. You'll run into Decorators a lot if you begin
using Python for Web Development, such as Flask or Django!

183
Lesson 2. Iterators and Generators (Udemy, n.d.)

In this section of the course we will be learning the difference between iteration and
generation in Python and how to construct our own Generators with the yield statement.
Generators allow us to generate as we go along, instead of holding everything in memory.

We've touched on this topic in the past when discussing certain built-in Python functions
like range(), map() and filter().

Let's explore a little deeper. We've learned how to create functions with def and the return
statement. Generator functions allow us to write a function that can send back a value and then
later resume to pick up where it left off. This type of function is a generator in Python,
allowing us to generate a sequence of values over time. The main difference in syntax will be
the use of a yield statement (Udemy, n.d.).

In most aspects, a generator function will appear very similar to a normal function. The
main difference is when a generator function is compiled they become an object that
supports an iteration protocol. That means when they are called in your code they don't
actually return a value and then exit. Instead, generator functions will automatically
suspend and resume their execution and state around the last point of value generation.
The main advantage here is that instead of having to compute an entire series of values up
front, the generator computes one value and then suspends its activity awaiting the next
instruction. This feature is known as state suspension (Udemy, n.d.).

To start getting a better understanding of generators, let's go ahead and see how we can
create some.

184
Now since we have a generator function we don't have to keep track of every single cube
we created.

Generators are best for calculating large sets of results (particularly in calculations that
involve loops themselves) in cases where we don’t want to allocate the memory for all of
the results at the same time (Udemy, n.d.).

Let's create another example generator which calculates fibonacci numbers:

What if this was a normal function, what would it look like?


185
Notice that if we call some huge value of n (like 100000) the second function will have to
keep track of every single result, when in our case we actually only care about the
previous result to generate the next one!

The next() and iter() built-in functions

A key to fully understand generators is the next() function and the iter() function.

The next() function allows us to access the next element in a sequence. Let us check it
out:

186
After yielding all the values next() caused a StopIteration error. What this error informs
us of is that all the values have been yielded(Udemy, n.d.).

You might be wondering that why don’t we get this error while using a for loop? A for
loop automatically catches this error and stops calling next().

Let's go ahead and check out how to use iter(). You remember that strings are iterables:

187
But that doesn't mean the string itself is an iterator! We can check this with the next()
function:

Interesting, this means that a string object supports iteration, but we can not directly
iterate over it as we could with a generator function. The iter() function allows us to do
just that!

Great! Now you know how to convert objects that are iterable into iterators themselves!

The main idea from this lecture is that using the yield keyword at a function will cause the
function to become a generator. This change can save you a lot of memory for large use
cases.

188
For more information on generators check out the following:

Stack Overflow Answer

Another StackOverflow Answer

Summary

From this module, we study the python generator and iterator and we can say every
generator is an iterator in Python, not every python iterator is a generator. Both come in
handy and have their own capabilities and advantages. In creating a python generator, we
use a function. But in creating an iterator in python, we use the iter() and next()
functions. A generator in python makes use of the
‘yield’ keyword while a python iterator doesn’t.

Furthermore, python generator saves the states of the local variables every time ‘yield’
pauses the loop in python. An iterator does not make use of local variables, all it needs is
iterable to iterate on. A generator may have any number of ‘yield’ statements. You can
implement your own iterator using a python class while a generator does not need a class
in python.

To write a python generator, you can either use a Python function or a


comprehension. But for an iterator, you must use the iter() and next() functions. Generator
in python let us write fast and compact code. This is an advantage over Python iterators.
They are also simpler to code than do custom iterator. Python iterator is more
memoryefficient.

189
Assessment Task 7.1

Decorators Homework

Since you will not run into decorators until further coding experiences, this homework is a test
on your interest on how Python shall be given consideration and attention. Your task is to submit
a short write ups of your understanding about the topics (Flask and Django) given below. Check
out the Web Framework Flask. You can use Flask to create web pages with. Python (as long as
you know some HTML and CSS) and they use decorators a lot!

Learn how they use view decorators. Don't worry if you don't completely understand everything
about Flask, the main point of this assessment is that you have an awareness of decorators in Web
Frameworks. That way if you decide to become a "Full-Stack" Python Web Developer, you won't
find yourself perplexed by decorators. You can also check out Django another (and more
popular) web framework for Python which is a bit more heavy duty.

190
Assessment Task 7.2

Iterators and Generators Homework

Problem 1

Create a generator that generates all the Odd numbers up to a given maximum
range entered
.

Problem 2

Using the yield keyword, create a number generator tha diplay “need” random
numbers from a specific range of number that are specified.
Note: Use the random library. For example:

191
Iterators and Generators Homework
Problem 3

With for loop statement, use iter() function convert the string below into an iterator
to display the output needed: Use error handling to stop displaying error message.

Reference

Udemy, (n.d) Complete-Python-3-Bootcamp-master/Complete-Python-3-


Bootcampmaster
https://www.udemy.com/course/complete-pythonbootcamp/learn/lecture/
9388522#content

END OF MIDTERM TERM MODULE


CHECK YOUR EXAM SCHEDULE

DO NOT FORGET TO TAKE THE EXAM AS SCHEDULED

192

You might also like