Python OOP



Yaolong Huang

Table of content

  1. Basics
  2. Class
  3. Object
  4. Inheritance
  5. Operator Overloading

Basics

In Python, everything is an object.

Everything is an instance of a class.

 # We can use type() to check the type of every object.
>>> type(1)
<type 'int'>
>>> dir(1)
['__abs__', '__add__', '__and__', '__class__', '__cmp__', '__coerce__', '__delattr__', '__div__', '__divmod__', '__doc__', '__float__', '__floordiv__', '__getattribute__', '__getnewargs__', '__hash__',
....]
>>> a = 1
>>> a.__abs__
<method-wrapper '__abs__' of int object at 0x985ef38>
>>> def test():
... pass
>>> type(test)
<type 'function'>
>>> test.__hash__
<method-wrapper '__hash__' of function object at 0xb7f8aae4>

Basics

To check whether a object is of certain class,

use isinstance.

 >>> isinstance(1, int)
True
>>> isinstance(1, bool)
False
>>> class Base(object):
... pass
>>> b = Base()
>>> isinstance(b, Base)
True

Class

You can use class keyword to define a new class.

class Base(object):
pass


To create an object of certain class,
call the class like it's a function.
 b = Base() # this creates a new object of class Base and assign it to b



Methods

To define a method in a class,

you just define the method like a normal function.

But you should add a self parameter before other parameters.

class Base(object):
def hello(self, msg):
print 'hello,', msg

b = Base()
b.hello('world!')

Self

class Base(object):
def hello(self, msg): # self?
print 'hello,', msg

What? You don't know what's self ?

self is yourself. It's like this in C++.

And yes, you have to write self yourself.
Python won't do it for you.

Data members

To define a data member in a class, what should you do?

You do nothing, just assign a value to it.

class Base(object):
def hello(self, msg):
self.msg = msg
print "hello,", self.msg

# and you can use it once it has been defined.
b = Base()
print b.msg # NO, it's not defined yet.
b.hello('world!')
print b.msg # YES, it's been defined.

Accessiblity

How about public/protected/private in C++?

Python do not provide these facilities.

But Python has a convention to do this.
class Base(object):
def hello(self, msg, times):
self.msg = msg # members without prefix is public
self.__times = times # members with "__" prefix is private
for _ in range(self.__times):
print "hello,", self.msg

b = Base()
b.hello('world!', 2)
b.msg # this is public, so you can use it outside.
b.__times # NO, it's private, so you cannot use it.

Accessiblity

What about protected?

class Base(object):
def hello(self, msg, times):
self.msg = msg # members without prefix is public
self._times = times # members with single "_" prefix is protected
for _ in range(self._times):
print "hello,", self.msg

b = Base()
b.hello('world!', 2)
print b._times # What?

Yeah, you still can use protected member outside.

In Python, protected member is a convention, you can ignore it.

But once you ignore it, Python will fool you.

Accessibility

The same access rule applies to methods of a class.

class Base(object):
def hello(self, msg, times): # this method is public
self.msg = msg
self._times = times

def __print_msg(self): # this method is private
for _ in range(self._times):
print "hello,", self.msg

b = Base()
b.hello()
b.__print_msg() # NO, this is a private method

But note that method which both begins and ends with "__" is not private. It's special method.

Initialization

What about constructor in C++?

class Base(object):
def __init__(self, arg1, arg2):
self.arg1 = arg1
self.__arg2 = arg2

b = Base(1, 2) # this will call __init__
print b.arg1

As you see, __init__ begins and ends with "__", so it's special.

Object

As mentioned before, we can create a new object of a class by "calling" the class.

And in Python, you can add attributes to an object after it's created.

class Base(object):
pass
b = Base()
b.data = 1 # This is okay.
print b.data

And this is a way to create a struct in Python.

Object

If you add a member/function to a object, other objects of the same class will not be affected.

class Base(object):
pass
b1 = Base()
b2 = Base()
b1.data = 1
print b2.data # NO, this does not work.

b1.fun = lambda a: a + 1
print b1.fun(2) # this is 3
print b2.fun(2) # NO, this does not work.

Object

Remember everything is object in Python?

Guess what?

Class in Python is also an object of certain class.

>>> class Base(object):
... pass
>>> type(Base)
<type 'type'>
>>> type(type(Base))
<type 'type'>

As you can see, a class is an instance of "type" class.

And yes, you can use a class as an object.

Base1 = Base
b = Base1() # This is okay.

Inheritance

Miss inheritance? Actually we have used inheritance before.

class Base(object):
pass

As you can see, the parent class is object.

If you want to derive anther class, just write it between "()".

class Derived(Base):
pass

Polymorphism

Pylymorphism is implemented as virtual function normally.

In Python, every method in a class is virtual.

class Base(object):
def hello(self):
print "Base: Hello"
 
class Derived(Base):
def hello(self): # overrides Base.hello
print "Derived: Hello"

b = Base()
b.hello() # this will print "Base: Hello"
d = Derived()
d.hello() # this will print "Derived: Hello"

Polymorphism

But private methods are not virtual.

class Base(object):
def hello(self):
self.__print("Hello")
def __print(self, msg):
print "Base:", msg
 
class Derived(Base):
def __print(self, msg): # DOES NOT override Base.hello
print "Derived:", msg

b = Base()
b.hello() # this will print "Base: Hello"
d = Derived()
d.hello() # this will also print "Base: Hello"

Initialization

What about the constructor?

Because constructor is special method, we can call it directly.

class Base(object):
def __init__(self):
self.a = 1
 
class Derived(Base):
def __init__(self):
Base.__init__(self) # this calls Base's constructor
self.b = 2

d = Derived()
print d.a
print d.b

And yes, this is the way in Python to call parent's method.

Multiple Inheritance

Yes, Python supports multiple inheritance.

class Base1(object):
def hello(self):
print "Base1: Hello"
class Base2(object):
def hello(self):
print "Base2: Hello"
class Derived(Base1, Base2):
pass
d = Derived()
d.hello() # this prints "Base1: Hello"

Why the above code calls Base1.hello?

This relates to MRO in Python.

Operator Overloading

In C++, we can use operator+ to overload the plus operator for a class.

In Python, operator overloading is implemented by special methods.

Remember? Special methods are the methods that both begins and ends with "__"(double underscores).

class Base(object):
def __init__(self, data):
self.data = data

def __add__(self, other):
return Base(self.data + other.data)

b1, b2 = Base(1), Base(2)
print b1 + b2

Operator Overloading

There are a lot of operators in Python you can overload.

You can check the full list here.

__add__( self, other) 
__sub__( self, other) 
__mul__( self, other) 
__mod__( self, other) 
__pow__( self, other[, modulo]) 
__and__( self, other) 
__xor__( self, other) 
__or__( self, other) 
...

RAII

  • In C++, RAII is a very useful and powerful feature.
  • In Python RAII is implemented by Context Manager.
  • Context Manager is new in Python 2.5.
  • It's used with with keyword.
class DBTransaction(object):
def __init__(self, db_handle):
self.__db_handle = db_handle

def __enter__(self):
self.__transaction = db_handle.create_transaction()
self.__transaction.begin()
return self.__transaction

def __exit__(self, exc_type, exc_value, traceback):
if exc_type is not None:
self.__transaction.roll_back()
else:
self.__transaction.commit()

RAII(Cont.)

from __future__ import with_statement # write this line if you're using Python 2.5

with DBTransaction(db_handle) as transaction:
transaction.query("select * from tbl1")
# other DB queries

# Here __exit__ method will be called to end the transaction.
print "DB transaction is done."

As you can see, Context Manager is a powerful feature to write fault tolerant software.

Q/A

Any question?

Thank You

Enjoy programming in Python!

Made with Slides.com