









Study with the several resources on Docsity
Earn points by helping other students or get them with a premium plan
Prepare for your exams
Study with the several resources on Docsity
Earn points to download
Earn points by helping other students or get them with a premium plan
Designing and implementing Python programs that deal with: 1. Functions 2. Recursion 3. OOP 1. Functions
Typology: Lecture notes
1 / 17
This page cannot be seen from the preview
Don't miss anything!










Designing and implementing Python programs that deal with:
**1. Functions
A functionis a group of statements that is executed when it is called from somepoint of the
program.
The following is its format:
where:
variableand which acts within the function as a regular local variable.They allow to pass
arguments to the function when it is called. The differentparameters are separated by
commas.
Consider the following code and examine the repeated code with same functionality
for i in range(30):
print("*" , end='')
print()
print("Object Oriented Programming")
for i in range(30):
print("*",end='')
print()
print("Lab 02")
for i in range(30):
print("*", end='')
print()
print("Department of Computer Science")
for i in range(30):
print("*",end='')
print()
What we will do in this case for similar functionality code, create a function named drawLine()
and call that function at repeated code loctations.
defdrawLine():
for i in range(30):
print("*" , end='')
print()
drawLine()
print("Artificial Intelligence")
drawLine()
print("Lab 02")
drawLine()
print("Department of Computer Science")
drawLine()
drawLine method with an argument to draw line according to the size provided
defdrawLine(n):
for i in range(n):
print("*" , end='')
print()
drawLine(30)
print("Artificial Intelligence")
drawLine(10)
“A recursive method is a method that either directly or indirectly makes a call to itself.” [Weiss].
It does this by making problem smaller (simpler) at each call.
Recursive functions have two important components:
the base case deals with the simplest possible form of the problem you're trying to solve.
Perhaps the simplest example is calculating factorial:
n! = n ∙ ( n − 1 ) ∙⋯ ∙ 2 ∙ 1
. However, we can
also see that n! = n ∙ ( n − 1 )!. Thus, factorial is defined in terms of itself.
For example,
factorial( 5 ) = 5 * factorial( 4 )
= 5 * ( 4 * factorial( 3 ) )
= 5 * ( 4 * (3 * factorial( 2 ) ) )
= 5 * ( 4 * (3 * (2 * factorial( 1 ) ) ) )
= 5 * ( 4 * (3 * (2 * ( 1 * factorial( 0 ) ) ) ) )
Iterative Solution Recursive Solution
def factorial( n ):
sum = 1
for i in range(1,n+1):
*sum = i;
return sum;
print("Factorial of 3 is
" ,factorial(3))
def factorial( n ):
if( n <= 1 ):
return 1
else:
return n * factorial( n-1 )
print("Factorial of 3 is
" ,factorial(6))
sum =11=*
sum =12=*
sum =23=*
return sum=
Designing and implementing Python programs that deal with:
**4. OOP Terminology
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 Employee:
'Common base class for all employees'
empCount = 0
def init(self, name, salary):
self.name = name
self.salary = salary
Employee.empCount += 1
def displayCount(self):
print ("Total Employee ", Employee.empCount)
def displayEmployee(self):
print ("Name : ", self.name, ", Salary: ", self.salary)
The variable empCount is a class variable whose value is shared among all instances of a
this class. This can be accessed as Employee.empCount from inside the class or outside
the class.
The first method init() is a special method, which is called class constructor or
initialization method that Python calls when you create a new instance of this class.
[Note: Pyton has only one constructor there are no overloaded constructors]
You declare other class methods like normal functions with the exception that the first
argument to each method is self. Python adds the self argument to the list for you; you do
not need to include it when you call the methods.
To create instances of a class, you call the class using class name and pass in whatever
arguments its init method accepts.
"This would create first object of Employee class"
emp1 = Employee("Zara", 2000)
"This would create second object of Employee class"
emp2 = Employee("Manni", 5000)
You access the object's attributes using the dot operator with object. Class variable would be
accessed using class name as follows −
emp1.displayEmployee()
emp2.displayEmployee()
print ("Total Employee ", Employee.empCount)
Now, putting all the concepts together −
class Employee:
'Common base class for all employees'
empCount = 0
def init(self, name, salary):
self.name = name
self.salary = salary
Employee.empCount += 1
def displayCount(self):
print ("Total Employee ", Employee.empCount)
def displayEmployee(self):
print ("Name : ", self.name, ", Salary: ", self.salary)
"This would create first object of Employee class"
emp1 = Employee("Zara", 2000)
"This would create second object of Employee class"
emp2 = Employee("Manni", 5000)
emp1.displayEmployee()
emp2.displayEmployee()
print ("Total Employee ", Employee.empCount)
When the above code is executed, it produces the following result −
Name : Zara ,Salary: 2000
Name : Manni ,Salary: 5000
Total Employee 2
You can add, remove, or modify attributes of classes and objects at any time −
emp1.age = 7 # Add an 'age' attribute.
emp1.age = 8 # Modify 'age' attribute.
def displayCount(self):
print ("Total Employee ", Employee.empCount)
def displayEmployee(self):
print ("Name : ", self.name, ", Salary: ", self.salary)
print ("Employee.doc:", Employee.doc)
print ("Employee.name:", Employee.name)
print ("Employee.module:", Employee.module)
print ("Employee.bases:", Employee.bases)
print ("Employee.dict:", Employee.dict)
When the above code is executed, it produces the following result −
Employee.doc: Common base class for all employees
Employee.name: Employee
Employee.module: main
Employee.bases: ()
Employee.dict: {'module': 'main', 'displayCount':
<function displayCount at 0xb7c84994>, 'empCount': 2,
'displayEmployee': <function displayEmployee at 0xb7c8441c>,
'doc': 'Common base class for all employees',
'init': <function init at 0xb7c846bc>}
Python deletes unneeded objects (built-in types or class instances) automatically to free the
memory space. The process by which Python periodically reclaims blocks of memory that no
longer are in use is termed Garbage Collection.
Python's garbage collector runs during program execution and is triggered when an object's
reference count reaches zero. An object's reference count changes as the number of aliases that
point to it changes.
An object's reference count increases when it is assigned a new name or placed in a container
(list, tuple, or dictionary). The object's reference count decreases when it's deleted with del , its
reference is reassigned, or its reference goes out of scope. When an object's reference count
reaches zero, Python collects it automatically.
a = 40 # Create object <40>
b = a # Increase ref. count of <40>
c = [b] # Increase ref. count of <40>
del a # Decrease ref. count of <40>
b = 100 # Decrease ref. count of <40>
c[0] = -1 # Decrease ref. count of <40>
You normally will not notice when the garbage collector destroys an orphaned instance and
reclaims its space. But a class can implement the special method del() , called a destructor,
that is invoked when the instance is about to be destroyed. This method might be used to clean
up any non memory resources used by an instance.
This del() destructor prints the class name of an instance that is about to be destroyed −
#!/usr/bin/python
class Point:
def __init( self, x=0, y=0):
self.x = x
self.y = y
def del(self):
class_name = self.class.name
print (class_name, "destroyed")
pt1 = Point()
pt2 = pt
pt3 = pt
print (id(pt1), id(pt2), id(pt3)) # prints the ids of the obejcts
del pt
del pt
del pt
When the above code is executed, it produces following result −
class Child(Parent): # define child class
def init(self):
print ("Calling child constructor")
def childMethod(self):
print ('Calling child method')
c = Child() # instance of child
c.childMethod() # child calls its method
c.parentMethod() # calls parent's method
c.setAttr(200) # again call parent's method
c.getAttr() # again call parent's method
When the above code is executed, it produces the following result −
Calling child constructor
Calling child method
Calling parent method
Parent attribute : 200
Similar way, you can drive a class from multiple parent classes as follows −
class A: # define your class A
class B: # define your class B
class C(A, B): # subclass of A and B
You can use issubclass() or isinstance() functions to check a relationships of two classes and
instances.
The issubclass(sub, sup) boolean function returns true if the given subclass sub is indeed a
subclass of the superclass sup.
The isinstance(obj, Class) boolean function returns true if obj is an instance of class Class or
is an instance of a subclass of Class
You can always override your parent class methods. One reason for overriding parent's methods
is because you may want special or different functionality in your subclass.
class Parent: # define parent class
def myMethod(self):
print ('Calling parent method')
class Child(Parent): # define child class
def myMethod(self):
print ('Calling child method')
c = Child() # instance of child
c.myMethod() # child calls overridden method
When the above code is executed, it produces the following result −
Calling child method
Following table lists some generic functionality that you can override in your own classes −
SN Method, Description & Sample Call
1 init ( self [,args...] )
Constructor (with any optional arguments)
Sample Call : obj = className(args)
2 del( self )
When the above code is executed, it produces the following result −
Vector(7,8)
An object's attributes may or may not be visible outside the class definition. You need to name
attributes with a double underscore prefix , and those attributes then are not be directly visible
to outsiders.
class JustCounter:
__secretCount = 0
def count(self):
self.__secretCount += 1
print (self.__secretCount)
counter = JustCounter()
counter.count()
counter.count()
print (counter.__secretCount)
When the above code is executed, it produces the following result −
Traceback (most recent call last):
File "test.py", line 12, in
print counter.__secretCount
AttributeError: JustCounter instance has no attribute
'__secretCount'
Python protects those members by internally changing the name to include the class name. You
can access such attributes as _object.className__attrName. If you would replace your last line
as following, then it works for you −
print counter._JustCounter__secretCount