Python OOP Concepts

It’s essential to understand OOP concepts since the usage is immense. OOP is related to concepts such as class, instance, attributes and methods.

Corey Schafer’s 6-video course is so far the best I stumble upon.

First, instance of a class and class, using his example in the video, creating an Employee class, emp_1 = Employee(), the emp_1 is an instance of the class. The first name, last name, pay and email address are the attributes of class. While the methods are designed to performance certain functions such as concatenating first name and last name into a full name.

class Employee()
def __init__(self, first, last, pay):
  self.first = first
  self.last = last = pay = first+'.'+last+'' 
def fullname(self):
  return '{}{}}'.format(self.first, self.last)

Then if you print(emp_1.fullname()), the whole name will be displayed, but if you remove the paranthesis, then only the attribute will be shown, object and location in memory. Note the self in paranthesis of fullname method, so it will execute accordingly to different input of emp instance. Note call an instance a method like emp_1.fullname() is equivalent to call a class passing along the instance like Employee.fullname(emp_1).

Now, to perform some more useful tasks, using the example where we need to apply pay raise each year, so a class variable method is created, note to pass a variable in class, we have to use the “attributes” way.

raise_amount = 1.04
def apply_raise(self): = int( * Employee.raise_amount) = int( * self.raise_amount)

The trick here is that if you pass the instance/emp_1, then it will check if there are any attributes directly associated to this instance, if not, it goes to the class to search. A good way to view is print(emp_1.__dict__), so all the attributes: {‘first’:’corey’, ‘pay’:50000, ’email’:’’,’last’:schafer’} is shown.

If change the class attribute by setting Employee.raise_amount = 1.05 then the whole employee instances Employee class all change to 1.05, while one can only set emp_1.raise_amount = 1.05, which only affects the particular instance emp_1. Note the key here is to pass self in pass_raise method, and then = int( * self.raise_amount).

The other scenario could be that it’s only correct to use Employee class instead of self. For example, the total number of employees, initially it is set to be

num_of_emps = 0
  Employee.num_of_emps += 1

2. is about class methods and static methods. Regular methods automatically take self/instance as parameters, while class method which is defined by putting an @classmethod in the front line, takes class as parameters, static methods don’t take in anything, just function like regular methods, but they are put below a class as for some logical connections.

def set_raise_amt(cls, amount):
  cls.raise_amt = amount

Employee.set_raise_amt(1.05), all employee instances will get the raise_amt to be new value 1.05.

People say they can use class method as alternative constructors, the following example illustrate what they actually mean. You see a string can be passed and quickly create new instance from class of Employee.

def from_string(cls, emp_str):
  first, ast, pay = emp_str.split('-')
  return cls(first, last, pay)
def is_workday(day):
  if day.weekeday() == 5 or day.weekdy() == 6:
    retrun False
  return True

3. Subclass and inheritance

class Developer(Employee):
  raise_amt = 1.10
  def __init__(self, first, last, pay, prog_lang):
    super().__init__(first, last, pay)
    Employee.__init__(self, first, last, pay)
    self.prog_lang = prog_lang
dev_1 = Developer('test','empl',60000, 'java')

class Manager(Employee):
  def __init_(self, first, last, pay, employees=None):
    super().__init__(firs,t last pay)
    if employees is None:
       self.employees = []
def print_emps(self):
  for emp in self.employees:

To find the detail use help function like below

isinstance(mgr_1, Manager)
issubclass(Developer, Employee)

4. Special, magic, dunder methods in class.

def repr(self):
return “employee(‘{}’, ‘{}’, {})”.format(self.first, self.last,
then if we print(emp_1)
instead of returning object at certain place in memory, it now returns

def str(self):
return ‘{} – {}’.format(self.fullname(),
print(emp_1) return str(emp_1)

def __add__(self, other):
  return +
print(emp_1 + emp_2)

Here is a real world example of dunder method

6. Property decorator – getter, setter and deleters.

When do we need to use these getter, setter and deleters? take the same example of employee class,

If we modify the first name by emp_1.firstname = ‘Jim’, the email attribute is put in an awkward situation, it still returns the previous first last name combined email address. You may think of an easy fix is to change the email form self attribute to a method like fullname, but it will alter how other users are using employee class, good developers intend to avoid such. This is when getter, setter and deleters come into play. It allows us to define a method, but accessable as an attribute.

If you want to feed in a modified input as first name last name comb, setter and deleter can be used as

def fullname(self):
  return '{} {}'.format(self.first, self.last)
def fullname(self, name):
  first, last = name.split(' ')
  self.first = first
  self.last = last
emp_1.full = 'newfirstname newlastname'
def fullname(self):
  print('delete name'
  self.first = None
  self.last = None
del emp_1.fullname

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.