Master Python OOP: Classes, Inheritance, Magic Methods & More
This comprehensive guide walks through Python's object‑oriented programming essentials, covering class definitions, attributes, common magic methods, inheritance, polymorphism, exception handling, as well as module and package creation and usage, complete with clear code examples for each concept.
1. Classes and Objects
Definition format using the class keyword, class attributes, __init__ initializer, instance methods, class methods, and static methods.
class ClassName:
# class attribute
class_attribute = "I am a class attribute"
# initializer
def __init__(self, param1, param2):
self.param1 = param1
self.param2 = param2
# instance method
def instance_method(self):
return f"Param1: {self.param1}, Param2: {self.param2}"
# class method
@classmethod
def class_method(cls):
return "This is a class method"
# static method
@staticmethod
def static_method():
return "This is a static method"Creating an object and accessing or adding attributes:
obj = ClassName("value1", "value2")
print(obj.param1) # value1
obj.new_attribute = "new_value"
print(obj.new_attribute) # new_value2. Common Magic Methods
Magic methods are special methods that start and end with double underscores. Common examples include __init__, __str__, __repr__, __len__, __call__, __getitem__, __setitem__, __iter__, and __next__.
class MyClass:
def __init__(self, value):
self.value = value
def __str__(self):
return f"MyClass with value: {self.value}"
def __repr__(self):
return f"MyClass({self.value})"
def __len__(self):
return len(self.value)
def __call__(self):
print(f"Called with value: {self.value}")
def __getitem__(self, index):
return self.value[index]
def __setitem__(self, index, value):
self.value[index] = value
def __iter__(self):
self.index = 0
return self
def __next__(self):
if self.index < len(self.value):
result = self.value[self.index]
self.index += 1
return result
else:
raise StopIteration
obj = MyClass([1, 2, 3])
print(obj) # MyClass with value: [1, 2, 3]
print(repr(obj)) # MyClass([1, 2, 3])
print(len(obj)) # 3
obj() # Called with value: [1, 2, 3]
print(obj[1]) # 2
obj[1] = 4
print(obj[1]) # 4
for item in obj:
print(item) # 1 4 33. Inheritance
Inheritance allows a subclass to acquire attributes and methods from a parent class.
class Animal:
def __init__(self, name):
self.name = name
def speak(self):
pass
class Dog(Animal):
def speak(self):
return f"{self.name} says Woof!"
class Cat(Animal):
def speak(self):
return f"{self.name} says Meow!"
dog = Dog("Buddy")
cat = Cat("Whiskers")
print(dog.speak()) # Buddy says Woof!
print(cat.speak()) # Whiskers says Meow!4. Public and Private Attributes
Public attributes are accessible directly; private attributes are prefixed with double underscores to trigger name mangling.
class MyClass:
def __init__(self):
self.public_attr = "Public"
self.__private_attr = "Private"
def get_private_attr(self):
return self.__private_attr
obj = MyClass()
print(obj.public_attr) # Public
# print(obj.__private_attr) # AttributeError
print(obj.get_private_attr()) # Private5. Polymorphism
Polymorphism lets different classes respond to the same method call, typically via method overriding.
class Animal:
def speak(self):
pass
class Dog(Animal):
def speak(self):
return "Woof!"
class Cat(Animal):
def speak(self):
return "Meow!"
def animal_sound(animal):
print(animal.speak())
dog = Dog()
cat = Cat()
animal_sound(dog) # Woof!
animal_sound(cat) # Meow!6. Class and Instance Attributes
Class attributes belong to the class itself and are shared by all instances; instance attributes belong to each object individually.
class MyClass:
class_attribute = "I am a class attribute"
def __init__(self, instance_attribute):
self.instance_attribute = instance_attribute
print(MyClass.class_attribute) # I am a class attribute
obj = MyClass("I am an instance attribute")
print(obj.instance_attribute) # I am an instance attribute7. Class Methods and Static Methods
Class methods receive the class ( cls) as the first argument; static methods receive no implicit first argument.
class MyClass:
class_attribute = "I am a class attribute"
@classmethod
def class_method(cls):
return f"Class method: {cls.class_attribute}"
@staticmethod
def static_method():
return "Static method"
print(MyClass.class_method()) # Class method: I am a class attribute
print(MyClass.static_method()) # Static method8. Exception Handling
Use try / except / else / finally to manage runtime errors, and define custom exception classes when needed.
try:
result = 10 / 0
except ZeroDivisionError as e:
print(f"Error: {e}")
else:
print("No error occurred")
finally:
print("This will always execute")
def divide(x, y):
try:
return x / y
except ZeroDivisionError as e:
print(f"Error in divide: {e}")
raise
try:
result = divide(10, 0)
except ZeroDivisionError as e:
print(f"Caught in main: {e}")
class MyCustomError(Exception):
def __init__(self, message):
super().__init__(message)
try:
raise MyCustomError("This is a custom error")
except MyCustomError as e:
print(f"Caught custom error: {e}")
def check_positive(value):
if value <= 0:
raise ValueError("Value must be positive")
return value
try:
result = check_positive(-10)
except ValueError as e:
print(f"Error: {e}")9. Modules
Modules are Python files that can be imported to organize and reuse code.
# mymodule.py
def greet(name):
return f"Hello, {name}!"
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
def greet(self):
return f"Hello, my name is {self.name} and I am {self.age} years old."Importing a module:
import mymodule
print(mymodule.greet("Alice"))Importing specific names:
from mymodule import greet, Person
print(greet("Alice"))
p = Person("Bob", 25)
print(p.greet())Controlling wildcard imports with __all__:
# mymodule.py
__all__ = ['greet']
def greet(name):
return f"Hello, {name}!"
def farewell(name):
return f"Goodbye, {name}!"
from mymodule import *
print(greet("Alice")) # works
# print(farewell("Alice")) # NameErrorThe __name__ variable indicates whether a module is run as a script or imported.
# mymodule.py
def greet(name):
return f"Hello, {name}!"
if __name__ == '__main__':
print(greet("Alice"))10. Packages
Packages are directories containing an __init__.py file, allowing hierarchical organization of modules.
mypackage/
__init__.py
module1.py
module2.pyImporting a package and its modules:
import mypackage
from mypackage import module1
from mypackage.module1 import some_functionSigned-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
