Python Object-Oriented Programming
From the very beginning, Python has been an object-oriented language. As a result, creating classes and objects in Python is straightforward. In this chapter, we will introduce Python's object-oriented programming (OOP) in detail.
If you are new to object-oriented programming (OOP) languages, you may need to first understand some of the basic features of OOP to form a foundational concept. This will help you learn Python’s OOP more easily.
Let’s start by briefly understanding some key characteristics of OOP.
Introduction to Object-Oriented Concepts
Class: Describes a collection of objects with the same properties and methods. It defines the attributes and methods shared by each object in that collection. Objects are instances of classes.
Method: Functions defined within a class.
Class Variable: Variables shared across all instances of a class. Defined inside the class but outside of methods. Class variables are typically not used as instance variables.
Data Member: Class or instance variables that hold data related to the class and its instances.
Method Overriding: If a method inherited from the parent class doesn’t meet the needs of the subclass, it can be rewritten. This process is called overriding.
Local Variable: A variable defined inside a method that is only accessible within that method.
Instance Variable: Variables defined in a class and associated with a particular instance of that class, usually prefixed with
self
.Inheritance: A derived class (child class) inherits fields and methods from its base class (parent class). Inheritance allows the derived class to be treated as if it were a base class object. For example, a
Dog
class derived from anAnimal
class simulates an "is-a" relationship (e.g., "a dog is an animal").Instantiation: The process of creating an instance (object) of a class.
Object: An instance of a class that contains data members (class and instance variables) and methods.
Compared to other programming languages, Python includes classes while trying not to introduce too much additional syntax or semantics.
Python classes provide all the fundamental OOP features: class inheritance, method overriding, and the ability to call base class methods from derived classes.
Objects in Python can hold any amount and type of data.
Class Definition
The syntax for defining a class is as follows:
class ClassName: <statement-1> . . . <statement-N>
Once a class is instantiated, its attributes can be accessed. In fact, after creating a class, its attributes can be accessed by referencing the class name.
Class Object
A class object supports two operations: attribute reference and instantiation.
Attribute references follow the same syntax as any other attribute reference in Python: obj.name
.
When a class is created, all names defined in the class namespace become valid attribute names. For example:
Example (Python 3.0+)
#!/usr/bin/python3 class MyClass: """A simple class example""" i = 12345 def f(self): return 'hello world' # Instantiating the class x = MyClass() # Accessing class attributes and methods print("The attribute i of MyClass is:", x.i) print("The method f of MyClass returns:", x.f())
This creates a new class instance and assigns it to the local variable x
. x
is an empty object.
The output of the above code will be:
The attribute i of MyClass is: 12345 The method f of MyClass returns: hello world
__init__()
Method
Classes have a special method named __init__()
, known as the constructor. This method is automatically called when a class is instantiated, like this:
def __init__(self): self.data = []
When a class defines an __init__()
method, it will automatically be called when an instance of the class is created. For example, when instantiating the class MyClass
, the __init__()
method will be invoked:
x = MyClass()
Of course, the __init__()
method can accept parameters, which can be passed during class instantiation:
Example (Python 3.0+)
#!/usr/bin/python3 class Complex: def __init__(self, realpart, imagpart): self.r = realpart self.i = imagpart x = Complex(3.0, -4.5) print(x.r, x.i) # Output: 3.0 -4.5
self
Represents the Instance of the Class
The only distinction between a class method and a regular function is that a class method must have an additional first parameter, typically named self
.
class Test: def prt(self): print(self) print(self.__class__) t = Test() t.prt()
The output of this example is:
<__main__.Test instance at 0x100771878> __main__.Test
Here, self
refers to the instance of the class, and self.__class__
refers to the class itself.
Customizing the self
Parameter
The name self
is not a Python keyword; you can use any other name, and the code will still work:
class Test: def prt(runoob): print(runoob) print(runoob.__class__) t = Test() t.prt()
The output will still be:
<__main__.Test instance at 0x100771878> __main__.Test
In Python, self
is a convention for naming the reference to the current instance. It allows methods to access and modify the attributes of the class instance.
Example
class MyClass: def __init__(self, value): self.value = value def display_value(self): print(self.value) # Creating an instance of the class obj = MyClass(42) # Calling the instance method obj.display_value() # Output: 42
In this example, self
refers to the instance of the class. It is used in the __init__
constructor to initialize the instance's attributes and in the display_value
method to access the instance's attributes. By using self
, class methods can access and modify the instance’s data and define the behavior of the class.
Class Methods in Python
In Python, class methods are defined using the def
keyword, similar to regular functions. However, there is one key difference: class methods must include self
as the first parameter, which represents the instance of the class.
Example (Python 3.0+)
#!/usr/bin/python3 # Class definition class People: # Define basic attributes name = '' age = 0 # Define private attributes (cannot be accessed directly outside the class) __weight = 0 # Define the constructor method def __init__(self, n, a, w): self.name = n self.age = a self.__weight = w def speak(self): print("%s says: I am %d years old." % (self.name, self.age)) # Instantiate the class p = People('runoob', 10, 30) p.speak()
Output:
runoob says: I am 10 years old.
Inheritance
Python supports inheritance, which is a crucial feature of object-oriented programming. Without inheritance, the concept of classes would lose much of its power. A derived class can inherit properties and methods from a base class. The syntax for inheritance is as follows:
class DerivedClassName(BaseClassName): <statement-1> . . . <statement-N>
A subclass (derived class) inherits the properties and methods of a parent class (base class). The base class name must be within the same scope as the derived class definition. Additionally, if the base class is in another module, an expression can be used, like this:
class DerivedClassName(modname.BaseClassName):
Example (Python 3.0+)
#!/usr/bin/python3 # Class definition class People: # Define basic attributes name = '' age = 0 # Define private attributes (cannot be accessed directly outside the class) __weight = 0 # Define the constructor method def __init__(self, n, a, w): self.name = n self.age = a self.__weight = w def speak(self): print("%s says: I am %d years old." % (self.name, self.age)) # Single inheritance example class Student(People): grade = '' def __init__(self, n, a, w, g): # Call the constructor of the parent class People.__init__(self, n, a, w) self.grade = g # Override the parent class's method def speak(self): print("%s says: I am %d years old and I am in grade %d." % (self.name, self.age, self.grade)) s = Student('Ken', 10, 60, 3) s.speak()
Output:
Ken says: I am 10 years old and I am in grade 3.
Multiple Inheritance
Python also supports limited multiple inheritance. The syntax for multiple inheritance is as follows:
class DerivedClassName(Base1, Base2, Base3): <statement-1> . . . <statement-N>
The order of base classes matters: when searching for a method, Python looks from left to right, stopping as soon as it finds the method in one of the base classes.
Example (Python 3.0+)
#!/usr/bin/python3 # Class definition class People: # Define basic attributes name = '' age = 0 # Define private attributes (cannot be accessed directly outside the class) __weight = 0 # Define the constructor method def __init__(self, n, a, w): self.name = n self.age = a self.__weight = w def speak(self): print("%s says: I am %d years old." % (self.name, self.age)) # Single inheritance example class Student(People): grade = '' def __init__(self, n, a, w, g): # Call the constructor of the parent class People.__init__(self, n, a, w) self.grade = g # Override the parent class's method def speak(self): print("%s says: I am %d years old and I am in grade %d." % (self.name, self.age, self.grade)) # Another class, preparing for multiple inheritance class Speaker: topic = '' name = '' def __init__(self, n, t): self.name = n self.topic = t def speak(self): print("My name is %s, I am a speaker, and my topic is %s." % (self.name, self.topic)) # Multiple inheritance class Sample(Speaker, Student): a = '' def __init__(self, n, a, w, g, t): Student.__init__(self, n, a, w, g) Speaker.__init__(self, n, t) test = Sample("Tim", 25, 80, 4, "Python") test.speak() # Since the method name is the same, Python calls the method from the first parent class (Speaker)
Output:
My name is Tim, I am a speaker, and my topic is Python.
In this example, Python calls the speak
method from the Speaker
class because it appears first in the class hierarchy of Sample
.
Method Overriding
If the functionality of a method in the parent class does not meet your needs, you can override it in the subclass. Here’s an example:
Example (Python 3.0+)
#!/usr/bin/python3 class Parent: # Define parent class def myMethod(self): print('Calling parent method') class Child(Parent): # Define child class def myMethod(self): print('Calling child method') c = Child() # Create an instance of the child class c.myMethod() # Call the overridden method in the child class super(Child, c).myMethod() # Use the child instance to call the overridden parent class method
The super()
function is used to call a method from the parent (super) class.
Output:
Calling child method Calling parent method
Class Attributes and Methods
Private Attributes
__private_attrs
: Attributes that start with two underscores are private and cannot be accessed directly outside the class. To use them inside the class, you useself.__private_attrs
.
Defining Methods in a Class
Class methods are defined using the def
keyword inside the class. A class method must include self
as the first parameter, representing the instance of the class.
The name
self
is a convention and can be replaced by another name likethis
, but it’s best to follow the standard.
Private Methods
__private_method
: Private methods start with two underscores and can only be called inside the class. They cannot be called from outside the class.
Example: Private Attributes
Example (Python 3.0+)
#!/usr/bin/python3 class JustCounter: __secretCount = 0 # Private variable publicCount = 0 # Public variable def count(self): self.__secretCount += 1 self.publicCount += 1 print(self.__secretCount) counter = JustCounter() counter.count() counter.count() print(counter.publicCount) print(counter.__secretCount) # Error: Cannot access private variable
Output:
1 2 2 Traceback (most recent call last): File "test.py", line 16, in <module> print(counter.__secretCount) # Error: Cannot access private variable AttributeError: 'JustCounter' object has no attribute '__secretCount'
Example: Private Methods
Example (Python 3.0+)
#!/usr/bin/python3 class Site: def __init__(self, name, url): self.name = name # Public attribute self.__url = url # Private attribute def who(self): print('Name : ', self.name) print('URL : ', self.__url) def __foo(self): # Private method print('This is a private method') def foo(self): # Public method print('This is a public method') self.__foo() x = Site('Tutorial', 'www.example.com') x.who() # Outputs normally x.foo() # Outputs normally x.__foo() # Error: Cannot call private method
Output:
Name : Tutorial URL : www.example.com This is a public method This is a private method Traceback (most recent call last): File "test.py", line 18, in <module> x.__foo() # Error AttributeError: 'Site' object has no attribute '__foo'
Special Methods in Classes
__init__
: Constructor method, called when an object is created.__del__
: Destructor method, called when an object is deleted.__repr__
: Converts an object to a string representation.__setitem__
: Sets an item by index.__getitem__
: Retrieves an item by index.__len__
: Returns the length of an object.__cmp__
: Compares two objects.__call__
: Enables an object to be called as a function.__add__
: Defines the addition behavior.__sub__
: Defines the subtraction behavior.__mul__
: Defines the multiplication behavior.__truediv__
: Defines the division behavior.__mod__
: Defines the modulo operation.__pow__
: Defines the exponentiation operation.
Operator Overloading
Python supports operator overloading, allowing you to define custom behavior for operators in your class. Here's an example:
Example (Python 3.0+)
#!/usr/bin/python3 class Vector: def __init__(self, a, b): self.a = a self.b = b def __str__(self): return 'Vector (%d, %d)' % (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)
Output:
Vector (7, 8)
This example demonstrates overloading the +
operator to add two vector objects.