Python - Lecture - 3 With Suitable Examples
Python - Lecture - 3 With Suitable Examples
Mr. Adeel-ur-Rehman
Scheme of Lecture
Object-Oriented Framework
Python Scopes and Namespaces
The self argument
The __init__ method
Classes
The __getitem__ and __setitem__ methods
Inheritance and Multiple Inheritance
Iterators and Generators
Exception Handling
Gui Tkinter Programming Basics
Object-Oriented Framework
Two basic programming paradigms:
Procedural
Organizing programs around functions or
blocks of statements which manipulate data.
Object-Oriented
combining data and functionality and wrap it
inside what is called an object.
Object-Oriented Framework
Classes and objects are the two main aspects
of object oriented programming.
A class creates a new type.
Where objects are instances of the class.
An analogy is that we can have variables of
type int which translates to saying that
variables that store integers are variables
which are instances (objects) of the int class.
Object-Oriented Framework
Objects can store data using ordinary
variables that belong to the object.
Variables that belong to an object or class are
called as fields.
Objects can also have functionality by using
functions that belong to the class. Such
functions are called methods.
This terminology is important because it helps
us to differentiate between a function which
is separate by itself and a method which
belongs to an object.
Object-Oriented Framework
Remember, that fields are of two types
they can belong to each instance (object) of the
class
or they belong to the class itself.
They are called instance variables and class
variables respectively.
A class is created using the class keyword.
The fields and methods of the class are listed
in an indented block.
The self
Class methods have only one specific
difference from ordinary functions
they have an extra variable that has to be added
to the beginning of the parameter list
but we do not give a value for this parameter
when we call the method.
this particular variable refers to the object itself,
and by convention, it is given the name self.
The self
Although, we can give any name for this
parameter, it is strongly recommended that
we use the name self.
Any other name is definitely frowned upon.
There are many advantages to using a
standard name
any reader of our program will immediately
recognize that it is the object variable i.e. the self
and even specialized IDEs (Integrated
Development Environments such as Boa
Constructor) can help us if we use this particular
name.
ASC, National Centre for Physics
Programming Python
The self
Python will automatically provide this value in
the function parameter list.
For example, if we have a class called
MyClass and an instance (object) of this
class called MyObject, then when we call a
method of this object as
MyObject.method(arg1, arg2), this is
automatically converted to
MyClass.method(MyObject, arg1, arg2).
This is what the special self is all about.
Creating a Class
class Person:
pass # A new block
p = Person()
print p
#<__main__.Person instance at 0x816a6cc>
Object Methods
class Person:
def sayHi(self):
print 'Hello, how are you?'
p = Person()
p.sayHi()
# This short example can also be
#written as Person().sayHi()
Inheritance
One of the major benefits of object
oriented programming is reuse of code
One of the ways this is achieved is
through the inheritance mechanism.
Inheritance can be best imagined as
implementing a type and subtype
relationship between classes.
Consider this example:
Using Inheritance
class SchoolMember:
'''Represents any school member.'''
def __init__(self, name, age):
self.name = name
self.age = age
print '(Initialized SchoolMember: %s)' % self.name
def tell(self):
print 'Name:"%s" Age:"%s" ' % (self.name,
self.age),
Using Inheritance
class Teacher(SchoolMember):
'''Represents a teacher.'''
def __init__(self, name, age, salary):
SchoolMember.__init__(self, name, age)
self.salary = salary
print '(Initialized Teacher: %s)' % self.name
def tell(self):
SchoolMember.tell(self)
print 'Salary:"%d"' % self.salary
Using Inheritance
class Student(SchoolMember):
'''Represents a student.'''
def __init__(self, name, age, marks):
SchoolMember.__init__(self, name, age)
self.marks = marks
print '(Initialized Student: %s)' % self.name
def tell(self):
SchoolMember.tell(self)
print 'Marks:"%d"' % self.marks
Using Inheritance
t = Teacher('Mrs. Abraham', 40, 30000)
s = Student('Swaroop', 21, 75)
print # prints a blank line
members = [t, s]
for member in members:
member.tell() # Works for instances of
Student as well as Teacher
Multiple Inheritance
Python supports a limited form of multiple
inheritance as well.
A class definition with multiple base classes looks as
follows:
class DerivedClassName(Base1, Base2, Base3):
<statement-1>
.
<statement-N>
The only rule necessary to explain the semantics is
the resolution rule used for class attribute
references.
Multiple Inheritance
This is depth-first, left-to-right. Thus, if an attribute
is not found in DerivedClassName, it is searched in
Base1, then (recursively) in the base classes of
Base1, and only if it is not found there, it is searched
in Base2, and so on.
A well-known problem with multiple inheritance is a
class derived from two classes that happen to have a
common base class. While it is easy enough to figure
out what happens in this case (the instance will have
a single copy of “instance variables” or data
attributes used by the common base class).
Iterators
By now, you’ve probably noticed that
most container objects can looped over
using a for statement:
for element in [1, 2, 3]:
print element
for element in (1, 2, 3):
print element
for key in {’one’:1, ’two’:2}:
print key
Iterators
for char in "123":
print char
for line in open("myfile.txt"):
print line
This style of access is clear, concise, and convenient.
The use of iterators pervades and unifies Python.
Behind the scenes, the for statement calls iter() on the
container object.
The function returns an iterator object that defines the
method next() which accesses elements in the container one
at a time.
When there are no more elements, next() raises a
StopIteration exception which tells the for loop to terminate.
This example shows how it all works:
Iterators
>>> s = ’abc’
>>> it = iter(s)
>>> it
<iterator object at 0x00A1DB50>
>>> it.next()
’a’
>>> it.next()
’b’
Iterators
>>> it.next()
’c’
>>> it.next()
Traceback (most recent call last):
File "<pyshell#6>", line 1, in -toplevel
it.next()
StopIteration
Iterators
Having seen the mechanics behind the
iterator protocol, it is easy to add
iterator behavior to our classes.
Define a __iter__() method which
returns an object with a next() method.
If the class defines next(), then
__iter__() can just return self:
Iterators
>>> class Reverse:
"Iterator for looping over a sequence
backwards"
def __init__(self, data):
self.data = data
self.index = len(data)
def __iter__(self):
return self
Iterators
def next(self):
if self.index == 0:
raise StopIteration
self.index = self.index - 1
return self.data[self.index]
Iterators
>>> for char in Reverse(’spam’):
print char
m
a
p
s
Generators
Generators are a simple and powerful tool for
creating iterators.
They are written like regular functions but
use the yield statement whenever they want
to return data.
Each time the next() is called, the generator
resumes where it left-off (it remembers all
the data values and which statement was last
executed).
An example shows that generators can be
trivially easy to create:
Generators
>>> def reverse(data):
for index in range(len(data)-1, -1, -1):
yield data[index]
>>> for char in reverse(’golf’):
print char
f
l
o
g
Generators
Anything that can be done with generators can also
be done with class based iterators as described in the
previous section.
What makes generators so compact is that the
__iter__() and next() methods are created
automatically.
Another key feature is that the local variables and
execution state are automatically saved between
calls.
This made the function easier to write and much
more clear than an approach using class variables
like self.index and self.data.
Generators
In addition to automatic method
creation and saving program state,
when generators terminate, they
automatically raise StopIteration.
In combination, these features make it
easy to create iterators with no more
effort than writing a regular function.
Exception Handling
Exceptions occur when certain exceptional
situations occur in our program.
For example, what if we are reading a file and
we accidentally deleted it in another window
or some other error occurred? Such situations
are handled using exceptions.
What if our program had some invalid
statements?
This is handled by Python which raises its
hands and tells you there is an error.
Exception Handling
Consider a simple print statement.
What if we misspelt print as Print?
Note the capitalization.
Exception Handling
To show the usage of exceptions, we will try to read
input from the user and see what happens.
>>> s = raw_input('Enter something --> ')
Enter something --> Traceback (most recent call
last): File "<stdin>", line 1, in ? EOFError
>>>
Here, we ask the user for input and if he/she presses
Ctrl-d i.e. the EOF (end of file) character, then
Python raises an error called EOFError.
Next, we will see how to handle such errors.
Exception Handling
We can handle exceptions using the
try..except statement.
We basically put our usual statements
within the try-block.
And we put all the error handlers in the
except-block.
Exception Handling
import sys
try:
s = raw_input('Enter something --> ')
except EOFError:
print '\nWhy did you do an EOF on me?' sys.exit() # Exit
the program
except:
print '\nSome error/exception occurred.'
# Here, we are not exiting the program
print 'Done'
Exception Handling
We put all the statements that might raise an error in
the try block
And then handle all errors and exceptions in the
except clause/block.
The except clause can handle a single specified error
or exception or a parenthesized list of
errors/exceptions.
If no names of errors or exceptions are supplied, it will
handle all errors and exceptions. There has to be at
least one except clause associated with every try
clause.
Exception Handling
If any error or exception is not handled,
then the default Python handler is
called which stops the execution of the
program and prints a message.
We can also have an else clause with
the try..catch block.
The else clause is executed if no
exception occurs.
Exception Handling
We can also get the exception object
so that we can retrieve additional
information about the exception which
has occurred.
This is demonstrated in the next
example.
Exception Handling
We can raise exceptions using the raise
statement
- we specify the name of the
error/exception and the exception object.
The error or exception that we can raise
should be a class which directly or
indirectly is a derived class of the Error or
Exception class respectively.
Exception Handling
class ShortInputException(Exception):
'''A user-defined exception class.'''
def __init__(self, length, atleast):
self.length = length
self.atleast = atleast
try:
s = raw_input('Enter something --> ')
if len(s) < 3:
raise ShortInputException(len(s), 3)
Exception Handling
Other work can go as usual here. except
EOFError:
print '\nWhy did you do an EOF on me?‘
except ShortInputException, x:
print ‘\nThe input was of length %d, it should
be at least %d'\ % (x.length, x.atleast)
else:
print 'No exception was raised.'
Exception Handling
Other work can go as usual here. except
EOFError:
print '\nWhy did you do an EOF on me?‘
except ShortInputException, x:
print ‘\nThe input was of length %d, it should
be at least %d'\ % (x.length, x.atleast)
else:
print 'No exception was raised.'
Exception Handling
What if we wanted some statements to
execute after the try block whether or
not an exception was raised?
This is done using the finally block.
Note that if we are using a finally
block, we cannot have any except
clauses for the same try block.
Exception Handling
try:
f = file('poem.txt')
while True: # Our usual file-reading block
l = f.readline()
if len(l) == 0:
break
print l,
finally:
print 'Cleaning up...'
f.close()
Tkinter Structure
Tkinter is the simply the name of Python’s
interface to Tk
-- a GUI library originally written for use with the
Tcl programming language.
Python’s Tkinter module talks to Tk, and the
Tk API in turn interfaces with the underlying
window system:
Microsoft Windows
X Windows on Unix
or Macintosh
Tkinter Structure
Python’s Tkinter adds a software layer on top
of Tk that allows Python scripts to call out to
Tk to build and configure interfaces, and
routes control back to Python scripts that
handle user-generated events (e.g., mouse-
clicks).
i.e., GUI calls are internally routed from
Python script, to Tkinter, to Tk; GUI events
are routed from Tk, to Tkinter, and back to a
Python script.
Tkinter Structure
Luckily, Python programmers don’t
normally need to care about all this call
routing going on internally;
They simply make widgets and register
Python functions to handle widget events.
Because of the overall structure, event
handlers are usually known as callback
handlers as the GUI library “calls back”
to Python code when events occur.
ASC, National Centre for Physics
Programming Python
Tkinter Structure
Python/Tkinter programs are entirely event-
driven:
They build displays and register handlers for
events, and then do nothing but wait for events to
occur.
During the wait, the Tk GUI library runs an event
loop that watches for mouseclicks, keyboard
presses, and so on.
All application program processing happens in the
registered callback handlers in response to events.