Object Oriented Programming

In all the programs we wrote till now, we have designed our program around functions i.e. blocks of statements to process data like using a calculator. This is called the procedure-oriented way of programming. There is another way of organizing your program which is to combine data and functionality and wrap it inside something called an object. This is called the object oriented programming paradigm. Most of the time you can use procedural programming, but when writing large programs or have a problem that is better suited to this method, you can use object oriented programming techniques.

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.

Essentially, an object is a collection of data, and functions that operate on that data. We've already been using objects in Python: list for example, list is an ordered sequence of data, list has many functions(methods) we can use to manipulate those data. , a number list or a string list are all examples of list objects.

To create new kinds of objects, you must first create a class. A class is essentially a blueprint for creating an object of a particular kind.

Too much dry talking, time for the real stuff:

The syntax of defining a class is ?simaler to a function:

class MyClassName:

    class variables...

    class functions...
  • Class names are usually capitalized, MyClassNameLikeThis, but this is only a convention, not a requirement
  • Everything in a class is indented, just like the code within a function, if statement, for loop. The first thing not indented is not in the class.

Using the class to create an object x = MyClassName() creates a new instance of the class and assigns this object to the local variable x.

Let's make a simple class to represent an apple, this class has only one variable color:

Ex. 11.1-1 apple.py

# apple.py
1 class Apple:           
2     color = 'red'          
3

>>>A1 = Apple()          # create an instance of Apple class and assign this object to variable A1
>>>print( A1.color )   # access the class variable color using dot notation
red                    # A1 has original color 'red'
>>>
>>>A1.color = 'green'    # change the value of the color variable to be 'green'
>>>print( A1.color)    # check the value for variable color again
green        # A1 has new color 'green'
>>>

The first line defines the class container, which starts with the keyword class and the class name, Apple, then a colon : ends the line.

All indented parts(4 spaces) are class suite (all the elements that comprise the class), at the second line here it' a class variable named color, which is set to a value of 'red'.

We create an Apple object, A1, it's an instance of Apple class. Every instance of the class will have the same variable color and start at the same value 'red'.

Now, on top of the above I will add a function announce() to Apple class:

Ex. 11.1-2 apple.py

# apple.py
1 class Apple:           
2    
3     def announce():
4         print("An apple a day keeps the doctor away!")
5     color = 'red'
6     variety = 'Fuji'
7

>>> a = Apple()       # a is an object of Apple class
>>> print("a: I'm a {0} {1} apple.".format(a.color, a.variety))
a: I'm a red Fuji apple.
>>>
>>> a.announce()
An apple a day keeps the doctor away!
>>>
>>> b = Apple()      # b is another object of Apple class
>>> print(b.color, b.variety)   # b gets its variables from Apple class, has values set as color 'red', variety 'Fuji'
red, Fuji  
>>>
>>> b.color = 'green'    # assign new value to b
>>> b.variety = 'Granny Smith'
>>> print("b: I'm a {0} {1} apple, great for making apple pie.".format(b.color, b.variety))  
b: I'm a green Granny Smith apple, great for making apple pie.
>>>

From the above examples we can say: a and b are both Apple objects, they are instances of Apple class. They all get variables color, variety and announce() function from Apple class.

An object combines variables and functions into a single entity. Objects get their variables and functions from classes. Classes are essentially templates for creating your objects.

Variables that belong to an object or class are referred to as fields.

Objects can also have functionality by using functions that belong to a class. Such functions are called methods of the class. Simply put, a method is a function defined inside a class.

This terminology is important because it helps us to differentiate between functions and variables which are independent and those which belong to a class or object. Collectively, the fields and methods can be referred to as the attributes of that class.

The Apple class has three attributes: two variables and one method.

11.2 Initialize class, __init__(self) function

?? class method , instance method,

In previous Apple class, it looks like we set the object's values (color and variety) by assigning values to the class variables(fields) when defining the class. But in fact, the standard way to initialize an object's values when creating objects is to define __init__( ) function in classes. In some OOP Languages, it's called a constructor.

__init__ is short for "initialize". __ is two underscores. __init__() always takes at least one argument (also the first argument), self, which refers to the object itself being created. The use of self is a universal convention in Python, some other languages, such as Java and C++, use-and require-the name this.

When a class defines an init() method, class instantiation automatically invokes init() for the newly-created class instance.

Now let's jump right into OOP by making a simple class representing a dog:

Ex. 11.2-1 dog.py

# dog.py
1 class Dog:
2     def __init__(self):
3         self.color = ' '
4         self.eyeNumber = 0
5

>>> d1 = Dog( )      # Create a Dog object, d1
>>> d1.color                
' '
>>> d1.eyeNumber
0
>>> d1.color = 'yellow'      # assign new value to d1
>>> d1.eyeNumber = 4
>>> dl.color                    
'yellow'
>>> p1.eyeNumber
4             # Use your imagination, a yellow dog with 4 EYEs!
>>>

So in this example, a new, initialized Dog instance can be obtained by d1 = Dog(), it has color ' '(empty string) and 0 eyes when created.

All classes should have an init(self) method as constructor, when you create a class without a constructor, Python automatically creates a default constructor for you that doesn't do anything.

When you create a class instance (an object), Python automatically calls init function only once to initializing an object's variables.

We can provide extra arguments(parameters) to init if needed.

In previous example, if we want to create a Dog object, d1, with particular? color and eye number, we must assign new value to d1 like d1.color ='yellow' and d1.eyeNumber=4 to make it like a real dog(Really? 4-eye-dog?).

A more convenient way to do the above is to pass information to the constructor. Since constructors are simply specially named functions, we can use parameters (as we’ve seen before) to provide the specific information.

We can make our class constructor more general by putting extra parameters into the __init__(self) method, use __init__(self, parameter1, parameter2) instead for greater flexibility. In that case, arguments given to the class instantiation operator are passed on to __init__(self, parameter1, parameter2). For example:

Let's rewrite the previous Dog class to allow for a more flexible initialization:

Ex. 11.2-2 dog.py

class Dog:
    def __init__(self, initColor, initEye):
        self.color = initColor
        self.eyeNumber = initEye

# Now we can create a Dog object d2 and initializing it in a much simpler way:

>>> d2 = Dog('black', 5)
>>> d2.eyeNumber
5
>>> d2.color
black      # A black 5-eye-dog, Ha! Anything is possible with Python

Here inside __init__() method, the initColor and initEye refer to the values passed into the constructor, and we assign those values to object variables(or instance variables) called color and eyeNumber using the self parameter, with the code

self.color = initColor self.eyeNumber = initEye

If we create a new Dog object, here d2, and display it's color and eyeNumber, you can see the initialization function in action.

We can also provide default values to the constructor: use __inin__(self, initColor=' ', initEye=0) instead of the previous __init__. So if we make an instant of Dog and forget to provide arguments, say d3=Dog(), by default, d3.color' has value ' '(empty string) and d3.eyeNumber is 0. If we didn't forget, then the values provided will be assigned to object variables the same way asd2 = Dog('black',5)` in previouse? example.

Another example to show how __init__(self, para=defaultValue) works.

Ex. 11.2-2 Robot.py

# Robot.py

class Robot:
    """ I'm a robot, depending on I have a name or not

    I can say hello with different message."""

    def __init___(self, name=None):
        self.name = name   

    def say_hello(self):
        if self.name:    # if name=None, returns False; if name has value, returns True
            print("Hi, I am {0}, what can I do for you?".format(self.name))
        else:
            print("Hi, I am a robot, I can not do anything for you before getting a name.")

>>> r = Robot()
>>> r.say_hello()
Hi, I am a robot, I can not do anything for you before getting a name.

>>> p = Robot('Buzz')
>>> p.say_hello()
HI, I am Buzz, what can I do for you?

11.3 add more methods to class

Same as __init__(self, otherParameters), all methods defined in a class that operate on objects of that class will have self as their first parameter. Again, this serves as reference to the object itself which in turn gives access to the state data inside the object. The self parameter is also a way for one function in the class to call another function in the class( and in the parent class, just wait and see).

Now let's add more methods to Dog class:

Ex. 11.3-1 dog.py

class Dog:'
    def __init__(self, initColor, initEye):
        self.color = initColor
        self.eyeNumber = initEye

    def say(self):
        return '"Woof, Woof, Woof!"'

d3 = Dog('white', 2)
print('I'm a {0} dog, I have {1} eyes and I will say: ".format(d3.color, d3.eyeNumber) )
print( d3.say() )

# Run...
I'm a white dog, I have 2 eyes and I will say:
"Woof, Woof, Woof!"     # Finally! a normal dog!

When we create an object of a class, such as d3, a Dog object, we refer to its variables or functions using objectName.attributesName such as d3.color, d3.eyeNumber and d3.say().

(More on self) But when we are doing things inside a class, such as making a new function, if we need to refer to variables and other functions, we use self.attributesName.

See example, remember docstring? :

Ex. 11.3-2 Wallet.py

# Wallet.py
class Wallet:
    """I have some base money in my Wallet.

    I earn more money to put in my Wallet."""

    def __init__(self, x = 0):
        self.total = x

    def earn(self, y = 0):
        self.total += y
        return self.total

    def earnTwice(self, z = 0):
        self.earn(z)
        self.earn(z)
        return self.total

myWallet= Wallet(5)
print( myWallet.total )
print( myWallet.earn(10) )
print( myWallet.earnTwice(20) )

# run...
5
15
55

Here in Wallet, in the constructor, we define object variable total and assign a value x to it. Then we define the second method earn(), in earn(), we refer to object variable total using self.total. The same thing, in the third method addTwice(), we may call other methods(earn()) by using method attributes of the self argument, self.earn().

Next similar example, I have a box of gumballs, I will put more gumballs into it. The numbers of gumballs are stored in a number list:

Ex. 11.3-3 box_gumballs.py

# box_gumballs.py

class Box:
    def __init__(self):
        self.numLst = []

    def add(self, x):
        self.numLst.append(x)
        return self.numLst

    def addTwice(self, x):
        self.add(x)
        self.add(x)
        return self.numLst

# run...
>>> b = Box()
>>> print(b.add(10))
[10]
>>> print(b.addTwice(15))
[10, 15, 15]

11.4 Setter , Getter,

some standard methods ,__str__()

, display(), __repr__(), ??property decorators?

Setter and getter methods are often used in most classes. The setter methods are for changing the data. The getter methods do not change the values of attributes, they just return the values. By doing these, the attributes of a class are made private to hide and protect them from other code. This is called encapsulation.

We will make a Person class, and add setter, getter methods to it:

Ex. 11.4-1 Person.py

# Person.py
class Person:
    def __init__(self, name=’Buzz’, age=1):
        self.name = name
        self.age = age
    def SetName(self, name):
        self.name = name
    def SetAge(self, age):
        self.age = age

    def GetName(self, name):
        return self.name
    def GetAge(self, age):
        return self.age

    def __str__ (self):
        return “ %s is aged %d.” % (self.name, self.age)

The above example, the Person class begins with the standard constructor __init__ function, when we create a Person object, it’s two instance variables: name and age will be initialized. If the user fails to provide these values, they default to ‘Buzz’ and 1. The SetName( ) and SetAge( ) are setters, GetName( ) and GetAge( ) are getters, they are the two types of accessors, provide write-only or read-only access to the underlying value.

?

__str__( ) method The last is a commonly used __str__( ) method in about every class for the users to be able to print the object, this method converts an object of the class into a string.

We can improve on this representation if we include a special method call str. Notice that this method uses the same naming convention as the constructor, that is two underscores before and after the name. It is common that Python uses this naming technique for special methods.

The str method is responsible for returning a string representation as defined by the class creator.

It is required that the str method create and return a string. print automatically use this when printing things(objects)

(??? override) ython provides many default implementations for methods that we as programmers will probably want to change. When a programmer changes the meaning of a special method we say that we override the method. Note also that the str type converter function uses whatever str method we provide.

Ex. 11.4-1 continued, Person.py

# use Person
>>>
>>>p1 = Person()
>>>print( p1 )
Buzz is aged 1.
>>>
>>> p1.setName('Sniffy')
>>> p1.setAge(3.5)
>>> 
>>> print( p1.getAge() )
3.5
>>> print( p1 )
Sniffy is aged 3.5

Use class in an different app, remember import?

Let’s use the Person class in another application. The Person class will be an external class, which means Person doesn’t exists within the confines of the application file. I put Person class in a file named MyClass (module) together with some other classes I made.

Ex. 11.4-2 PersonTest.py

# PersonTest.py

>>>Import MyClass
>>>P1 = MyClass.Person ( )

>>>P2 = MyClass.Person ('Sera', 20)                 

>>>print( P1.GetName ( ) )                                   Buzz                 
>>>print( P1.GetAge ( ) )                                                       1  

>>>P1.SetName( ‘Avery’ )
>>>P1.SetAge( 12 )
>>>print( P1 )                                                         Avery is aged  12.
>>>print( P2 )
Sera is aged 20.

>>>P2.SetName ( ‘Emma’ )
>>>P2.SetAge ( 14 )
>>>print ( P2 )                                                                         Emma is aged 14.

++++ ??? end here??

11.5 Pro Topic

Instance variable and Class variable

results matching ""

    No results matching ""