Object-Oriented Programming (OOP)
Classes and Objects in Python
Object-oriented programming (OOP) is a programming style that organizes code around "objects" - instances of classes. A class defines structure and behavior, while objects are concrete instances of this structure.
Defining a class
class Student:
pass
Creating an object
John = Student()
print(type(John)) # Output: <class '__main__.Student'>
- A class is a user-defined data type.
- Objects are instances of classes and can have their own attributes and methods.
- With OOP, code becomes more modular, reusable, and easier to maintain.
The __init__ Constructor in Python
The __init__ method is the constructor of a class in Python. It is called automatically when an
object is created and allows attribute initialization.
Defining a constructor
class Student:
def __init__(self, name, age):
self.name = name
self.age = age
Creating an object with a constructor
John = Student("John", 17)
print(John.name) # Output: John
print(John.age) # Output: 17
selfis a reference to the current instance of the class.- The constructor can accept any number of parameters, depending on what you want to initialize.
- Without
__init__, the object is created but has no defined attributes.
Attributes and Methods in Python
Attributes are variables associated with an object, while methods are functions defined within a class. They define the state and behavior of objects.
Instance attributes
class Student:
def __init__(self, name, age):
self.name = name
self.age = age
John = Student("John", 17)
print(John.name) # Output: John
Instance methods
class Student:
def __init__(self, name):
self.name = name
def greet(self):
print(f"Hello, I am {self.name}!")
John = Student("John")
John.greet() # Output: Hello, I am John!
- Attributes define the state of an object.
- Methods define behavior and can access attributes via
self. - You can modify attributes directly:
John.age = 18.
Inheritance and Polymorphism in Python
Inheritance allows a class to acquire the behavior and attributes of another class. Polymorphism allows using the same methods in different ways depending on the object context.
Class inheritance
class Person:
def __init__(self, name):
self.name = name
def greet(self):
print(f"Hello, I am {self.name}")
class Student(Person):
def greet(self):
print(f"Student {self.name} says hello!")
Polymorphism
pers = Person("Anna")
student = Student("John")
pers.greet() # Hello, I am Anna
student.greet() # Student John says hello!
- Inheritance is done using parentheses:
class Subclass(BaseClass). - Methods can be overridden in the subclass for customized behavior.
- Polymorphism allows handling different objects through the same interface.
Encapsulation and Properties in Python
Encapsulation is the OOP principle that protects the internal data of an object. In Python, we can control access to attributes using conventions and properties.
Private attributes (convention)
class Student:
def __init__(self, name):
self._name = name # convention: "protected" attribute
self.__code = 1234 # "private" attribute (name mangling)
Controlled access with properties
class Student:
def __init__(self, name):
self._name = name
@property
def name(self):
return self._name
@name.setter
def name(self, value):
if value:
self._name = value
John = Student("John")
print(John.name) # Output: John
John.name = "Andrew"
print(John.name) # Output: Andrew
- Attributes with
_or__are not completely private, but signal protection intent. - Decorators
@propertyand@setterallow control over reading and modifying attributes. - Encapsulation helps maintain data integrity and hide internal details.
Special Methods (dunder methods) in Python
Special methods, also known as "dunder methods" (double underscore), allow defining custom behavior for objects in common contexts: display, length, addition, etc. They start and end with two underscore characters.
__str__ - textual representation
class Student:
def __init__(self, name):
self.name = name
def __str__(self):
return f"Student: {self.name}"
John = Student("John")
print(John) # Output: Student: John
__len__ - object length
class Group:
def __init__(self, members):
self.members = members
def __len__(self):
return len(self.members)
g = Group(["John", "Anna", "Michael"])
print(len(g)) # Output: 3
__add__ - behavior of the + operator
class Student:
def __init__(self, name):
self.name = name
def __add__(self, other):
return f"{self.name} and {other.name} are classmates"
e1 = Student("John")
e2 = Student("Anna")
print(e1 + e2) # Output: John and Anna are classmates
- Special methods allow natural integration of objects into Python expressions.
__str__is used byprint()for display.__len__allows using thelen()function on custom objects.__add__defines how objects behave when added with+.
