Overview of OOP Terminology
Class β A user-defined prototype for an object that defines a set of attributes that characterize any object of the class. The attributes are data members (class variables and instance variables) and methods, accessed via dot notation.
Class variable β A variable that is shared by all instances of a class. Class variables are defined within a class but outside any of the class’s methods. Class variables are not used as frequently as instance variables are.
Data member β A class variable or instance variable that holds data associated with a class and its objects.
Function overloading β The assignment of more than one behavior to a particular function. The operation performed varies by the types of objects or arguments involved.
Instance variable β A variable that is defined inside a method and belongs only to the current instance of a class.
Inheritance β The transfer of the characteristics of a class to other classes that are derived from it.
Instance β An individual object of a certain class. An object obj that belongs to a class Circle, for example, is an instance of the class Circle.
Instantiation β The creation of an instance of a class.
Method β A special kind of function that is defined in a class definition.
Object β A unique instance of a data structure that is defined by its class. An object comprises both data members (class variables and instance variables) and methods.
Operator overloading β The assignment of more than one function to a particular operator.
Define a class
class Dog:
# Class attribute
# shared accross all instances and can be changed
species = "Canis familiaris"
# Constructor (with any optional arguments)
# Sample Call : obj = className(args)
def __init__(self,name,age):
# instance attributes
self.name=name
self.age=age
# Destructor, deletes an object
# Sample Call : del obj
def __del__(self):
class_name = self.__class__.__name__
print(class_name, "destroyed")
def __new__(cls):
print ("__new__ magic method is called")
inst = object.__new__(cls)
return inst
# Instance method
def description(self):
return f"{self.name} is {self.age} years old"
def setWeight(self,weight):
# data hiding with double underscore
self.__weight=weight
def getWeight(self):
return self.__weight
def setColor(self,color):
self._color=color # protected method
# Another instance method
def speak(self, sound):
return f"{self.name} says {sound}"
# __cmp__ ( self, x )
# Object comparison
# Sample Call : cmp(obj, x)
def __cmp__(self,other):
return True if self.name==other.name else False
# Overloading Operators
# a+b
def __add__(self,other):
return self.age+other.age
# magic/dunder methods
# Printable string representation
# Sample Call : str(obj)
def __str__(self):
return f"{self.name} is {self.age} years old"
# Evaluatable string representation
# Sample Call : repr(obj)
def __repr__(self):
return f"{self.name} is {self.age} years old"
>>> miles = Dog("Miles", 4)
>>> print(miles)
'Miles is 4 years old'
Child class
class BullDog(Dog):
# method overriding
def speak(self, sound="Arf"):
return f"{self.name} says {sound}"
We can use issubclass() or isinstance() functions to check a relationships of two classes and instances.
The issubclass(sub, sup) boolean function returns True, if the given subclass sub is indeed a subclass of the superclass sup.
The isinstance(obj, Class) boolean function returns True, if obj is an instance of class Class or is an instance of a subclass of Class
>>> jack = Bulldog("Jack", 3)
>>> isinstance(miles, BullDog)
False
>>> isinstance(jack, Dog)
False
class Employee:
empCount = 0
# constructor
def __init__(self, name, salary):
self.name = name
self.salary = salary
Employee.empCount += 1
def displayCount(self):
print("Total Employee %d" % Employee.empCount)
def displayEmployee(self):
print("Name : ", self.name, ", Salary: ", self.salary)
emp1 = Employee("Zara", 2000)
emp2 = Employee("Manni", 5000)
emp1.displayEmployee()
emp2.displayEmployee()
print("Total Employee %d" % Employee.empCount)
print(id(emp1)) # prints the id of the object
Output:
Name : Zara ,Salary: 2000
Name : Manni ,Salary: 5000
Total Employee 2
3782888
You can add, remove, or modify attributes of classes and objects at any time β
emp1.age = 7 # Add an 'age' attribute.
emp1.age = 8 # Modify 'age' attribute.
del emp1.age # Delete 'age' attribute.
Instead of using the normal statements to access attributes, you can use the following functions β
The getattr(obj, name[, default]) β to access the attribute of object.
The hasattr(obj,name) β to check if an attribute exists or not.
The setattr(obj,name,value) β to set an attribute. If attribute does not exist, then it would be created.
The delattr(obj, name) β to delete an attribute.
hasattr(emp1, ‘age’) # Returns true if ‘age’ attribute exists
getattr(emp1, ‘age’) # Returns value of ‘age’ attribute
setattr(emp1, ‘age’, 8) # Set attribute ‘age’ at 8
delattr(empl, ‘age’) # Delete attribute ‘age’
Built-In Class Attributes
Every Python class keeps following built-in attributes and they can be accessed using dot operator like any other attribute β
dict β Dictionary containing the class’s namespace.
doc β Class documentation string or none, if undefined.
name β Class name.
module β Module name in which the class is defined. This attribute is “main” in interactive mode.
bases β A possibly empty tuple containing the base classes, in the order of their occurrence in the base class list.
For the above class let us try to access all these attributes β
print "Employee.__doc__:", Employee.__doc__
print "Employee.__name__:", Employee.__name__
print "Employee.__module__:", Employee.__module__
print "Employee.__bases__:", Employee.__bases__
print "Employee.__dict__:", Employee.__dict__
To delete an object
del emp1
classmethod() in Python
class Person:
# create a variable
name = "Ohidur"
# create a function
def print_name(obj):
print("The name is : ", obj.name)
# create print_name classmethod
# before creating this line print_name()
# It can be called only with object not with class
Person.print_name = classmethod(Person.print_name)
# now this method can be called as classmethod
# print_name() method is called a class method
Person.print_name()
The @classmethod and @staticmethod Decorator:
from datetime import date
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
# a class method to create a
# Person object by birth year.
@classmethod
def fromBirthYear(cls, name, year):
return cls(name, date.today().year - year)
# a static method to check if a
# Person is adult or not.
@staticmethod
def isAdult(age):
return age > 18
person1 = Person('mayank', 21)
person2 = Person.fromBirthYear('mayank', 1996)
print (person1.age)
print (person2.age)
# print the result
print (Person.isAdult(22))
Output:
21
22
True
Python property() function
# Python program to explain property() function
# Alphabet class
class Alphabet:
def __init__(self, value):
self._value = value
# getting the values
def getValue(self):
print('Getting value')
return self._value
# setting the values
def setValue(self, value):
print('Setting value to ' + value)
self._value = value
# deleting the values
def delValue(self):
print('Deleting value')
del self._value
value = property(getValue, setValue, delValue, )
# passing the value
x = Alphabet('GeeksforGeeks')
print(x.value)
x.value = 'GfG'
del x.value
Output:
Getting value
GeeksforGeeks
Setting value to GfG
Deleting value
Using @property decorator
# Python program to explain property()
# function using decorator
class Alphabet:
def __init__(self, value):
self._value = value
# getting the values
@property
def value(self):
print('Getting value')
return self._value
# setting the values
@value.setter
def value(self, value):
print('Setting value to ' + value)
self._value = value
# deleting the values
@value.deleter
def value(self):
print('Deleting value')
del self._value
# passing the value
x = Alphabet('Peter')
print(x.value)
x.value = 'Diesel'
del x.value
Python dataclass
Data classes are just regular classes that are geared towards storing state, more than contain a lot of logic. Every time you create a class that mostly consists of attributes you made a data class.
What the dataclasses
module does is make it easier to create data classes. It takes care of a lot of boiler plate for you.
This is especially important when your data class must be hashable; this requires a __hash__
method as well as an __eq__
method. If you add a custom __repr__
method for ease of debugging, that can become quite verbose:
class InventoryItem:
'''Class for keeping track of an item in inventory.'''
name: str
unit_price: float
quantity_on_hand: int = 0
def __init__(
self,
name: str,
unit_price: float,
quantity_on_hand: int = 0
) -> None:
self.name = name
self.unit_price = unit_price
self.quantity_on_hand = quantity_on_hand
def total_cost(self) -> float:
return self.unit_price * self.quantity_on_hand
def __repr__(self) -> str:
return (
'InventoryItem('
f'name={self.name!r}, unit_price={self.unit_price!r}, '
f'quantity_on_hand={self.quantity_on_hand!r})'
def __hash__(self) -> int:
return hash((self.name, self.unit_price, self.quantity_on_hand))
def __eq__(self, other) -> bool:
if not isinstance(other, InventoryItem):
return NotImplemented
return (
(self.name, self.unit_price, self.quantity_on_hand) ==
(other.name, other.unit_price, other.quantity_on_hand))
With dataclasses
you can reduce it to:
from dataclasses import dataclass
@dataclass(unsafe_hash=True)
class InventoryItem:
'''Class for keeping track of an item in inventory.'''
name: str
unit_price: float
quantity_on_hand: int = 0
def total_cost(self) -> float:
return self.unit_price * self.quantity_on_hand
The same class decorator can also generate comparison methods (__lt__
, __gt__
, etc.) and handle immutability.
namedtuple
classes are also data classes, but are immutable by default (as well as being sequences). dataclasses
are much more flexible in this regard, and can easily be structured such that they can fill the same role as a namedtuple
class
The PEP was inspired by the attrs
project, which can do even more (including slots, validators, converters, metadata, etc.).
If you want to use dataclasses
module in Python versions < 3.7, then you could install the backported module (requires 3.6) or use the attrs
project mentioned above.