Lecture 14 Classes and Methods

1. Object-oriented features


Python is an object-oriented programming language, which means that it provides features that support object-oriented programming. It is not easy to define object-oriented programming, but we have already seen some of its characteristics:
• Programs are made up of object definitions and function definitions, and most of the computation is expressed in terms of operations on objects.
• Each object definition corresponds to some object or concept in the real world, and the functions that operate on that object correspond to the ways real-world objects interact.

Methods are just like functions, with two differences:
• Methods are defined inside a class definition in order to make the relationship between the class and the method explicit.
• The syntax for invoking a method is different from the syntax for calling a function.

Examples of printing objects:
(PLEASE note that, the parentheses after the 'class Time' at the top of the script is redundant. It was used often in older versions of python)
Please note that '%.2d' makes '09' happen in the results. If you have '%.3d', it will show you '009' in the results.
You can put the printing function into the class Time() as a method.
The two scripts got the same results. The first method has the class 'Time()' and the function 'print_time()' working independently. However, the second method has the function embedded into the class Time() and acts as a 'method' of the class Time(). In that case, the function can be called as an attribute of the class and being called as 'Time.print_time()' in the script (the dot notation).

There are several ways can be used to get the result for this simple example. But only the last one is being used often since it allows multiple objects/instances to be created for the same class.
To remove the confusion, I drew the chart below to show you all the possible combinations between the ways to call the method and the ways to declare the method:



The green lines indicate the combinations that worked without any errors.
Here are these scripts and results. Below is the fisrt combination showed in the chart.



Then the second:



The third:



The fourth:



The fifth:



The sixth:



Now, let's think about why the first two cases won't work.
Here is the chart again:



The first one didn't work because the Class Time doesn't have these attributes.
The second one didn't work becasuse of the same problem.

The third one and the fourth one worked because there is a variable being passed to the function and that variable has these required attributes.

The fifth one and the sixth one also worked because the instance 'time' passed it's attributes into the method. They both worked but we usually use the SIXTH one.

By convention, the first parameter of a method is called 'self', so it would be more common to write print_time like the sixth one.

The textbook made a very intuitive explanation on the differences among these methods:
The reason for this convention is an implicit metaphor:
 • The syntax for a function call, print_time(start), suggests that the function is the active agent. It says something like, “Hey print_time! Here’s an object for you to print.”
 • In object-oriented programming, the objects are the active agents. A method invocation like start.print_time() says “Hey start! Please print yourself.

But sometimes shifting responsibility from the functions onto the objects makes it possible to write more versatile functions (or methods), and makes it easier to maintain and reuse code

2. One more example

Look at the following example and try to understand why we use 'self' there:



3. Problems of when attributes are defined GLOBALLY in a class

When we set an attribute on an instance which has the same name as a class attribute, we are overriding the class attribute with an instance attribute, which will take precedence over it. If we create two Person objects and call the mark_as_deceased method on one of them, we will not affect the other one. We should, however, be careful when a class attribute is of a mutable type – because if we modify it in-place, we will affect all objects of that class at the same time. Remember that all instances share the same class attributes:

It is called a Class Variable.



What we should do in cases like this is initialize the mutable attribute as an instance attribute, inside the __init__() function. Then every instance will have its own separate copy:
The '__init__()' function will be executed automatically when the new object is instantiated.

Constructors are generally used for instantiating an object.The task of constructors is to initialize(assign values) to the data members of the class when an object of class is created.In Python the __init__() method is called the constructor and is always called when an object is created.



This is just a simple example. Details of how to use '__init__()' will be covered in future lectures.



Tasks:

1. Which Of The Following Represents A Distinctly Identifiable Entity In The Real World?
A. A class
B. An object
C. A method
D. A data field

2. Which Of The Following Represents A Template, Blueprint, Or Contract That Defines Objects Of The Same Type?
A. A class
B. An object
C. A method
D. A data field

3. Which Of The Following Is Required To Create A New Instance Of The Class?
A. A constructor
B. A class
C. A value-returning method
D. A None method

4. What Will Be The Output Of The Following Code Snippet?
class Sales:
    def __init__(self, id):
          self.id = id
          id = 100
val = Sales(123)
print (val.id)

A. SyntaxError, this program will not run
B. 100
C. 123
D. None of the above

5. Create a class called 'Employee', use the __inti__ function (constructor) to define attributes: name, age, and skills. Define a method called 'skillSet()' inside the class that prints out this: The employee XX can do XX programming. Define another method called 'peopleAge()' to print out this: The employee XX is XX years old. Instantiate an object from this class and run both methods for the results.

6. Create another class called Staff. Use the __init__ function to define the following attributes: first, last, and pay. Inside the __init__ function, also setup a counter to calculate the No. of employees for this company (for example make variable 'cnt' as a Class variable). The __init__ function is being executed everytime you instantiate a new object so the counter can be added to 1 every time being called. Define a method to print out the full name of an employee. Define another function to calculate/print out the pay after tax (the tax rate is 30% for example). Instantiate an object from this class and run both methods for the results. Print the number of Staff you instantiated.