Teaching notes OOP in python

Declaration of a class

[33]:
class Person:
    pass

create an instance of the class

[ ]:
p = Person()

Creating an initializer

[34]:
class Person:
    def __init__(self):
        pass
The init method and any other method should always have self as a first parameter.
Informally this is equevalent to the Java constructor, but actually the new method is the contructor in python.
The init does not create the object, but recieves it through the self parameter.

Instance and class variables

Instance attributes are defined in the init method or in another method.
They are denoted with the self prefix.
[8]:
class Person:
    def __init__(self, name):
        self.name = name # -> instance variable

Class methods can be defined outside or inside any method. Typically you will declare them as the firt elements after the class declaration line. They are not denoted by self, and they are shared by all object created from the class.

[9]:
class Person:

    type = 'Mammel' # class variable (no self in front of)

    def __init__(self, name):
        self.name = name # -> instance variable

Eksample:

[14]:
p = Person('Claus')
[15]:
p.type
[15]:
'Mammel'
[16]:
p.name
[16]:
'Claus'
[17]:
s = Person('Reptile')
[18]:
s.type
[18]:
'Mammel'
[19]:
s.name
[19]:
'Reptile'

Add / Change instance variables after declaration

You can at runtime add variables (and methods) to your object

[21]:
p = Person('Claus')
[22]:
p.__dict__   # __dict__ is used to get a dictionary of all instance variables
[22]:
{'name': 'Claus'}
[23]:
p.age = 23
p.sirname = 'Henningen'
[24]:
p.__dict__
[24]:
{'name': 'Claus', 'age': 23, 'sirname': 'Henningen'}

Add / Change class variables after declaration

[26]:
Person.name = 'Kim'

Eksample:

[27]:
class Animal:
    name = 'Fido'
[28]:
dog = Animal()
cat = Animal()
[29]:
dog.name
[29]:
'Fido'
[30]:
cat.name
[30]:
'Fido'
[31]:
Animal.name = 'Esther'
[32]:
dog.name
[32]:
'Esther'
[33]:
cat.name
[33]:
'Esther'

Overruling the class variable

[40]:
cat.name = 'Hannah'
[41]:
dog.name
[41]:
'Esther'
[42]:
cat.name
[42]:
'Hannah'
[43]:
cat.__dict__
[43]:
{'name': 'Hannah'}
[44]:
dog.__dict__
[44]:
{}

@Overloading (or this is not realy what we do)

We will use *args and kwargs for this and you can read about it here

“Overloading” in python is done by using the *args, and kwargs arguments

[55]:
def __init__(self, *args):
    if len(args) == 1:
        self.name = args[0]
    elif len(args) == 2:
        self.name = args[0]
        self.sirn = args[1]
    else:
        raise NotImplemented

Another option is to use deault values for your parameters

[1]:
def __init__(self, name=None, age=None):
    if name != None:
        self.name = name
    if age != None:
        self.age = age

Inheritance

The most simple approach to inheritance in python is:

[6]:
class Person:
    def __init__(self):
        self.name = 'Claus'
[7]:
class Student(Person):
   pass
[8]:
student = Student()
student.name
[8]:
'Claus'

If you define an __init__ method in your subclass you need to do the following:

[9]:
class Person:
    def __init__(self, name):
        self.name = name
[10]:
class Student(Person):
    def __init__(self, name):
        super().__init__(name)
[11]:
s = Student('Claus')

In Python You can inherite from multible classes

[45]:
class Instructor:
    def __init__(self, course):
        pass

class Student(Person, Instructor):
    def __init__(self, name, course):
        Person.__init__(self, name)        # different syntax on multiple inheritance
        Instructor.__init__(self, course)

s = Student('Claus', 'Co23')