Python has been an object-oriented language since its inception. Therefore, creating and using classes and objects in Python is simple and easy. This article will help you understand Python’s object-oriented programming support with examples. If you have no experience with object-oriented programming (OOP), check out an introductory course or tutorial to understand the basic concepts.
Table of Contents
Creating classes
The class
operator creates a new definition of a class. The class name immediately follows the class
keyword, followed by a colon:
class ClassName:
"""Optional class documentation string" ""
class_suite
- The class has a documentation string that can be accessed via
ClassName.__doc__
. the class_suite
consists of class parts, data attributes, and a function.
An example of creating a class in Python:
employeeclass
"""Base class for all employees"" "
emp_count = 0
def __init__(self, name, salary)
self.name = name
self.salary = salary
Employee.emp_count += 1
def display_count(self)
print('Total employees: %d' % Employee.empCount)
def display_employee(self)
print('Name: {}. Salary: {}'.format(self.name, self.salary))
- The variable
emp_count
is a class variable whose value is shared between instances of this class. You can access this variable throughEmployee.emp_count
from the class or outside the class. - The first method
__init__()
is a special method called the class constructor or initialization method. It is called by Python when creating a new instance of that class. - Declare the other methods of the class as normal functions, except that the first argument for each method is
self
. Python adds theself
argument to the list for you; and then you don’t need to include it when you call these methods.
Creating instances of a class
To create instances of classes, you need to call the class using its name and pass the arguments that the __init__
method takes.
# This will create the first object of the Employee class
emp1 = Employee("Andrew", 2000)
# This will create the second object of the Employee class
emp2 = Employee("Maria", 5000)
Accessing Attributes
Access class attributes using the .
operator after the class object. You can access a class using the name of the class variable:
emp1.display_employee()
emp2.display_employee()
print("Total employees: %d" % Employee.emp_count)
Now, systematize everything.
employeeclass
"""Base class for all employees"" "
emp_count = 0
def __init__(self, name, salary)
self.name = name
self.salary = salary
Employee.emp_count += 1
def display_count(self)
print('Total employees: %d' % Employee.emp_count)
def display_employee(self)
print('Name: {}. Salary: {}'.format(self.name, self.salary))
# This will create the first object of the Employee class
emp1 = Employee("Andrew", 2000)
# This will create the second object of class Employee
emp2 = Employee("Maria", 5000)
emp1.display_employee()
emp2.display_employee()
print("Total employees: %d" % Employee.emp_count)
When we execute this code, we get the following result:
Name: Andrei. Salary: 2000
Name: Maria. Salary: 5000
Total employees: 2
You can add, remove, or change class and object attributes at any time.
emp1.age = 7 # Adds the 'age' attribute
emp1.age = 8 # Change the 'age'attribute
del emp1.age # Deletes the 'age'attribute
Instead of using the usual operators to access attributes, you can use these functions:
getattr(obj, name [, default])
– to access an object attribute.hasattr(obj, name)
– check ifobj
has thename
attribute.setattr(obj, name, value)
– set the attribute. If the attribute does not exist, it will be created.delattr(obj, name)
– remove the attribute.
hasattr(emp1, 'age') # returns true if the 'age' attribute exists
getattr(emp1, 'age') # returns the value of the 'age' att ribute
setattr(emp1, 'age', 8) # sets the 'age' attribute to 8
delattr(empl, 'age') # removes the 'age'attribute
Embedded class attributes
Every Python class stores built-in attributes, and provides access to them through the operator .
operator, just like any other attribute:
__dict__
is the dictionary containing the class namespace.__doc__
is the documentation string of the class.None
if there is no documentation.__name__
– class name.__module__
– name of the module where the class is defined. This attribute is__main__
in interactive mode.__bases__
– can be empty tuple, containing base classes, in the order they appear in the base class list.
For the class above, let’s try to access all of these attributes:
employeeclass
"""Base class for all employees"" "
emp_count = 0
def __init__(self, name, salary)
self.name = name
self.salary = salary
Employee.empCount += 1
def display_count(self)
print('Total employees: %d' % Employee.empCount)
def display_employee(self)
print('Name: {}. Salary: {}'.format(self.name, self.salary))
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__)
When this code is executed, it returns this result:
Employee.__doc__: Base class for all employees
Employee.__name__: Employee
Employee.__module__: __main__
Employee.__bases__: (<class 'object'>,)
Employee.__dict__: {'__module__': '__main__', '__doc__': 'Base class for all employees', 'emp_count': 0, '__init__': <function Employee.__init__ at 0x03C7D7C8>, 'display_count': <function Employee.display_count at 0x03FA6AE0>, 'display_employee': <function Employee.display_employee at 0x03FA6B28>, '__dict__': <attribute '__dict__' of 'Employee' objects>, '__weakref__': <attribute '__weakref__' of 'Employee' objects>}
Deleting objects (garbage collection)
Python automatically removes unnecessary objects (built-in types or class instances) to free up memory space. Using the ‘Garbage Collection’ process, Python periodically recovers blocks of memory that are no longer in use. The Python garbage collector runs at runtime and when the number of references to an object reaches zero. As the number of calls to it changes, the number of references changes. When an object is assigned to a new variable or added to a container (list, tuple, dictionary), the number of object references increases. The number of references to an object decreases when it is deleted with del
, or its reference goes out of scope. When the number of references reaches zero, Python automatically collects it.
a = 40 # created an <40> object
b = a # increases the number of references <40>
c = [b] # increment the number of links <40>
del a # decreases the number of links <40>
b = 100 # decreases the number of links <40>
c[0] =-1 # decreases the number of links <40>
Normally you won’t notice when the garbage collector destroys an instance and clears its space. But the class can implement a special __del__()
method called the destructor. It is called before destroying the instance. This method can be used to clean up any memory resources. An example of how __del__() works The __del__()
destructor tells you the class name of the instance to be destroyed:
class Point
def __init__(self, x=0, y=0)
self.x = x
self.y = y
def __del__(self)
class_name = self.__class__.__name__
print('{} destroyed'.format(class_name))
pt1 = Point()
pt2 = pt1
pt3 = pt1
print(id(pt1), id(pt2), id(pt3)) # print id of the objects
del pt1
del pt2
del pt3
When the above code is executed and outputs the following:
17692784 17692784 17692784
Point destroyed
Ideally, you should create your classes in a separate module. Then import them into the main program module with
import SomeClass
.
Class inheritance in python
Inheritance is the process whereby one class inherits the attributes and methods of another. The class whose properties and methods are inherited is called a Parent or Superclass. And the class whose properties are inherited is the child class or Subclass.
Instead of starting from scratch, you can create a class based on an existing one. Specify the parent class in parentheses after the name of the new class. The descendant class inherits the attributes of its parent class. You can use these attributes as if they were defined in the descendant class. It can override the parent’s data elements and methods.
Class Inheritance Syntax
Inheritor classes are declared in the same way as parent classes. Only, the list of inherited classes, is specified after the class name.
class SubClassName(ParentClass1[, ParentClass2, ...]):
"""Optional class documentation string" ""
class_suite
Example of class inheritance in Python
class Parent: # declare parent class
parent_attr = 100
def __init__(self)
print('Parent constructor call')
def parent_method(self)
print('Parent method call')
def set_attr(self, attr)
Parent.parent_attr = attr
def get_attr(self)
print('Parent attribute:{}'.format(Parent.parent_attr))
class Child(Parent): # declare heir class
def __init__(self)
print('Calling the constructor of the heir class')
def child_method(self)
print('Call the method of the heir class')
c = Child() # an instance of the Child class
c.child_method() # call child_method
c.parent_method() # call parent_method
c.set_attr(200) # call parent_method again
c.get_attr() # call the parent method again
When this code runs, it outputs the following result:
Calling a constructor of an inherited class
Calling a method of an inherited class
Call of a parent method
Parent attribute: 200
Similarly, you can control a class with multiple parent classes:
class A: # declare class A
...
class B: # declare class B
...
class C(A, B): # C inherits from A and B
...
You can use issubclass()
or isinstance()
to check the relationship of two classes and instances.
- The logic function
issubclass(sub, sup)
returnsTrue
if the given subclasssub
is indeed a subclass ofsup
. - The logical function
isinstance(obj, Class)
returnsTrue
ifobj
is an instance ofClass
or is an instance of a subclass of Class.
Overriding methods
You can always override methods of the parent class. You may need special functions in your subclass. This is one reason for overriding parent methods. An example of overriding methods:
class Parent: # declare parent class
def my_method(self)
print('Parent method call')
class Child(Parent): # declare heir class
def my_method(self)
print('Heir method call')
c = Child() # an instance of the Child class
c.my_method() # method overridden by heir class
When this code is executed, it produces the following result:
Calling an inherited method
Popular Basic Methods
This table lists some common functions. You can override them in your own classes.
№ | Method, description and example call |
---|---|
1 | __init__(self [, args...]) – constructor (with any optional arguments) obj = className(args) |
2 | __del__(self) – the destructor, deletes the object del obj |
3 | __repr__(self) – program representation of the object repr(obj) |
4 | __str__(self) – string representation of the object str(obj) |
An example of using __add__
Suppose you created a Vector
class to represent two-dimensional vectors. What happens when you use an additional operator to add them? Python will probably be against it. However, you can define a __add__
method in your class to add vectors and the +
operator will behave as it should.
vectorclass
def __init__(self, a, b)
self.a = a
self.b = b
def __str__(self)
return 'Vector ({}, {})'.format(self.a, self.b)
def __add__(self, other)
return Vector(self.a + other.a, self.b + other.b)
v1 = Vector(2, 10)
v2 = Vector(5,-2)
print(v1 + v2)
When you execute this code, we get:
Vector(7, 8)
Private methods and attributes
Class attributes may not be visible outside of the class definition. You need to specify attributes with __
first, and those attributes will not be called outside the class. An example of a private attribute:
class JustCounter
__secret_count = 0
def count(self)
self.__secret_count += 1
print(self.__secret_count)
counter = JustCounter()
counter.count()
counter.count()
print(counter.__secret_count)
When you execute this code, we have the following result:
1
2
Traceback (most recent call last):
File "test.py", line 12, in <module>
print(counter.__secret_count)
AttributeError: 'JustCounter' object has no attribute '__secret_count'
You can access such attributes as object._className__attrName
. If you replace your last line with the following, it will work.
...
print(counter._JustCounter__secret_count)
When you execute the code, you get the result:
1
2
2