Mastering Advanced Python for Efficient Programming
Classes and Objects in Python
Class: Think of a class as a blueprint or a recipe.
Just like a recipe tells you how to make a cake, a class tells the
computer how to create something.
Object: An object is like the actual cake you make
using the recipe. It’s a specific instance of the class.
Real-Life Example
Imagine you have a blueprint for building a toy car. This blueprint is
the class. When you use the blueprint to build an actual toy car, that
toy car is an object.
Class: “Imagine you have a drawing that shows how to
make a toy car. This drawing is called a ‘class.’ It tells you
everything you need to know to make the toy car.”
Object: “Now, when you actually build the toy car
using the drawing, the toy car you made is called an ‘object.’ It’s a
real thing you can play with!”
Python Code Example
# Define a class called ToyCar
class ToyCar:
def __init__(self, color, size):
self.color = color
self.size = size
def drive(self):
print(f"The {self.color} toy car is driving!")
# Create an object of the ToyCar class
my_toy_car = ToyCar("red", "small")
# Use the object
my_toy_car.drive()
In this example:
- ToyCar is the class (the blueprint).
- my_toy_car is the object (the actual toy car).
Five Different Examples
- Class: Animal, Object: Dog
- Class: Book, Object: Harry Potter
- Class: House, Object: My House
- Class: Phone, Object: iPhone
- Class: Car, Object: Tesla Model S
Attributes and Methods in Python
Attributes: Think of attributes as the
characteristics or properties of an object. They are like the details
that describe the object.
Methods: Methods are actions that objects can
perform. They are like the things the object can do.
Real-Life Example
Imagine you have a pet dog. The dog’s attributes are things like its
name, color, and age. The methods are the actions the dog can do, like
barking or fetching a ball.
Attributes: “Imagine you have a pet dog. The dog’s
name is ‘Buddy,’ its color is brown, and it is 3 years old. These
details about Buddy are called ‘attributes.’”
Methods: “Now, Buddy can do things like bark and
fetch a ball. These actions Buddy can do are called ‘methods.’”
Python Code Example
# Define a class called Dog
class Dog:
def __init__(self, name, color, age):
self.name = name # Attribute
self.color = color # Attribute
self.age = age # Attribute
def bark(self): # Method
print(f"{self.name} is barking!")
def fetch(self): # Method
print(f"{self.name} is fetching the ball!")
# Create an object of the Dog class
my_dog = Dog("Buddy", "brown", 3)
# Use the object's methods
my_dog.bark()
my_dog.fetch()
In this example:
- name, color, and age are attributes (characteristics of the dog).
- bark and fetch are methods (actions the dog can perform).
Five Different Examples
- Class: Car, Attributes: color, model, year; Methods: drive, honk
- Class: Book, Attributes: title, author, pages; Methods: read, bookmark
- Class: Phone, Attributes: brand, model, battery_life; Methods: call, text
- Class: Student, Attributes: name, grade, student_id; Methods: study, take_exam
- Class: Plant, Attributes: species, height, age; Methods: grow, photosynthesize
Understanding Encapsulation in Python
Encapsulation: Encapsulation is like putting all the important things related to an object inside a box. This box keeps everything together and protects it from the outside world. In programming, encapsulation means bundling the data (attributes) and the methods (functions) that operate on the data into a single unit, which is usually a class.
Real-Life Example
Imagine you have a toy box. Inside this toy box, you keep all your toy
cars and the instructions on how to play with them. The toy box keeps
everything organized and safe.
Encapsulation: “Imagine you have a special toy box.
Inside this box, you keep all your toy cars and the instructions on
how to play with them. This toy box keeps everything together and
makes sure nothing gets lost. In programming, we do something similar
by putting all the important information and actions related to an
object inside a class.”
Python Code Example
# Define a class called ToyBox
class ToyBox:
def __init__(self):
self.toys = [] # Attribute to store toys
def add_toy(self, toy): # Method to add a toy
self.toys.append(toy)
print(f"{toy} has been added to the toy box.")
def list_toys(self): # Method to list all toys
print("Toys in the box:")
for toy in self.toys:
print(toy)
# Create an object of the ToyBox class
my_toy_box = ToyBox()
# Use the object's methods
my_toy_box.add_toy("Red Car")
my_toy_box.add_toy("Blue Truck")
my_toy_box.list_toys()
In this example:
- The ToyBox class encapsulates the toys attribute and the methods add_toy and list_toys.
- The toys attribute stores the list of toys.
- The add_toy method allows adding a new toy to the box.
- The list_toys method lists all the toys in the box.
Real-Life Examples of Encapsulation
-
Bank Account
- Class: BankAccount
- Attributes: account_number, balance
- Methods: deposit, withdraw, check_balance
- Explanation: A bank account class keeps the account number and balance private. The methods allow you to deposit money, withdraw money, and check the balance, ensuring that the balance is updated correctly and securely.
-
School
- Class: School
- Attributes: name, students
- Methods: add_student, remove_student, list_students
- Explanation: A school class keeps the name of the school and the list of students. The methods allow adding and removing students and listing all students, keeping the student data organized and protected.
-
Library
- Class: Library
- Attributes: books
- Methods: add_book, remove_book, list_books
- Explanation: A library class keeps a list of books. The methods allow adding and removing books and listing all books, ensuring that the book collection is managed properly.
-
Smartphone
- Class: Smartphone
- Attributes: brand, model, apps
- Methods: install_app, uninstall_app, list_apps
- Explanation: A smartphone class keeps the brand, model, and list of installed apps. The methods allow installing and uninstalling apps and listing all installed apps, managing the phone’s functionality.
-
Recipe Book
- Class: RecipeBook
- Attributes: recipes
- Methods: add_recipe, remove_recipe, list_recipes
- Explanation: A recipe book class keeps a list of recipes. The methods allow adding and removing recipes and listing all recipes, keeping the recipe collection organized.
Understanding Inheritance in Python
Inheritance: Inheritance is like a family trait that gets passed down from parents to children. In programming, inheritance allows one class (the child class) to inherit attributes and methods from another class (the parent class).
Real-Life Example
Imagine you have a family where the parents have certain traits, like
eye color and hair color. These traits can be passed down to their
children.
Inheritance: “Imagine you have a family. Your parents
have certain traits, like brown eyes and curly hair. You might inherit
these traits from your parents. In programming, we do something
similar by allowing one class to inherit traits (attributes and
methods) from another class.”
Python Code Example
# Define a parent class called Animal
class Animal:
def __init__(self, name):
self.name = name # Attribute
def speak(self): # Method
print(f"{self.name} makes a sound.")
# Define a child class called Dog that inherits from Animal
class Dog(Animal):
def speak(self): # Method
print(f"{self.name} barks.")
# Create an object of the Dog class
my_dog = Dog("Buddy")
# Use the object's method
my_dog.speak()
In this example:
- Animal is the parent class with an attribute name and a method speak.
- Dog is the child class that inherits from Animal and overrides the speak method to provide a specific implementation for dogs.
Real-Life Examples of Inheritance
-
Vehicles
- Parent Class: Vehicle
- Attributes: make, model
- Methods: start, stop
- Child Class: Car
- Methods: honk
- Explanation: A Car class can inherit the attributes and methods from the Vehicle class and add its own specific method like honk.
-
Electronics
- Parent Class: ElectronicDevice
- Attributes: brand, power
- Methods: turn_on, turn_off
- Child Class: Smartphone
- Methods: make_call, send_message
- Explanation: A Smartphone class can inherit the attributes and methods from the ElectronicDevice class and add its own specific methods like make_call and send_message.
-
Employees
- Parent Class: Employee
- Attributes: name, employee_id
- Methods: work, take_break
- Child Class: Manager
- Methods: conduct_meeting
- Explanation: A Manager class can inherit the attributes and methods from the Employee class and add its own specific method like conduct_meeting.
-
Plants
- Parent Class: Plant
- Attributes: species, height
- Methods: grow
- Child Class: Flower
- Methods: bloom
- Explanation: A Flower class can inherit the attributes and methods from the Plant class and add its own specific method like bloom.
-
Musical Instruments
- Parent Class: Instrument
- Attributes: name, type
- Methods: play
- Child Class: Guitar
- Methods: strum
- Explanation: A Guitar class can inherit the attributes and methods from the Instrument class and add its own specific method like strum.
Understanding Polymorphism in Python
Polymorphism: Polymorphism is like having a magic wand that can transform into different tools depending on what you need. In programming, polymorphism allows us to use a common interface to interact with different data types or objects.
Real-Life Example
Imagine you have a remote control that can operate different devices
like a TV, a fan, and a toy car. Even though the devices are
different, you can use the same remote control to interact with all of
them.
Polymorphism: “Imagine you have a special remote
control. This remote control can be used to turn on the TV, start the
fan, and drive a toy car. Even though the TV, fan, and toy car are
different things, you can use the same remote control to operate all
of them. In programming, we do something similar by using a common
interface to interact with different objects.”
Python Code Example
# Define a parent class called Animal
class Animal:
def speak(self):
pass
# Define child classes that inherit from Animal
class Dog(Animal):
def speak(self):
return "Bark"
class Cat(Animal):
def speak(self):
return "Meow"
class Cow(Animal):
def speak(self):
return "Moo"
# Function to make an animal speak
def make_animal_speak(animal):
print(animal.speak())
# Create objects of different classes
dog = Dog()
cat = Cat()
cow = Cow()
# Use the common interface to interact with different objects
make_animal_speak(dog)
make_animal_speak(cat)
make_animal_speak(cow)
In this example:
- Animal is the parent class with a method speak.
- Dog, Cat, and Cow are child classes that inherit from Animal and provide their own implementation of the speak method.
- The function make_animal_speak uses the common interface speak to interact with different objects.
Real-Life Examples of Polymorphism
-
Drawing Shapes
- Parent Class: Shape
- Method: draw
- Child Classes: Circle, Square, Triangle
- Method Implementation: Each class provides its own way to draw the shape.
- Explanation: You can use the draw method to draw any shape, whether it’s a circle, square, or triangle.
-
Payment Systems
- Parent Class: Payment
- Method: process_payment
- Child Classes: CreditCardPayment, PayPalPayment, BankTransferPayment
- Method Implementation: Each class processes the payment in its own way.
- Explanation: You can use the process_payment method to handle payments, regardless of the payment method.
-
File Handling
- Parent Class: File
- Method: open
- Child Classes: TextFile, ImageFile, AudioFile
- Method Implementation: Each class opens the file in its own way.
- Explanation: You can use the open method to open any type of file, whether it’s a text file, image file, or audio file.
-
Transportation
- Parent Class: Vehicle
- Method: move
- Child Classes: Car, Bicycle, Boat
- Method Implementation: Each class moves in its own way.
- Explanation: You can use the move method to make any vehicle move, whether it’s a car, bicycle, or boat.
-
Communication Devices
- Parent Class: CommunicationDevice
- Method: send_message
- Child Classes: Phone, Email, Radio
- Method Implementation: Each class sends a message in its own way.
- Explanation: You can use the send_message method to send a message, whether it’s through a phone, email, or radio.
Understanding Abstraction in Python
Abstraction: Abstraction is like a magic trick where you only see the amazing result without knowing how it was done. In programming, abstraction means hiding the complex implementation details and showing only the necessary features of an object.
Real-Life Example
Imagine you have a TV remote. You press a button to change the
channel, but you don’t need to know how the remote sends signals to
the TV. You just see the channel change.
Abstraction: “Imagine you have a TV remote. When you
press a button, the channel changes. You don’t need to know how the
remote works inside; you just need to know which button to press. In
programming, we do something similar by hiding the complex details and
showing only what you need to use.”
Python Code Example
from abc import ABC, abstractmethod
# Define an abstract class called RemoteControl
class RemoteControl(ABC):
@abstractmethod
def press_button(self):
pass
# Define a concrete class that inherits from RemoteControl
class TVRemote(RemoteControl):
def press_button(self):
print("Changing the TV channel")
# Create an object of the TVRemote class
my_remote = TVRemote()
# Use the object's method
my_remote.press_button()
In this example:
- RemoteControl is an abstract class with an abstract method press_button.
- TVRemote is a concrete class that inherits from RemoteControl and provides an implementation for the press_button method.
- The user interacts with the press_button method without needing to know how it works internally.
Real-Life Examples of Abstraction
-
Coffee Machine
- Class: CoffeeMachine
- Method: make_coffee
- Explanation: When you press a button to make coffee, you don’t need to know how the machine grinds the beans and brews the coffee. You just get your coffee.
-
Car
- Class: Car
- Method: start_engine
- Explanation: When you turn the key or press a button to start the car, you don’t need to know how the engine works. You just need to know how to start it.
-
Smartphone
- Class: Smartphone
- Method: take_photo
- Explanation: When you press a button to take a photo, you don’t need to know how the camera processes the image. You just get the photo.
-
ATM Machine
- Class: ATM
- Method: withdraw_money
- Explanation: When you enter your PIN and request money, you don’t need to know how the ATM processes the transaction. You just get your cash.
-
Music Player
- Class: MusicPlayer
- Method: play_song
- Explanation: When you press play, you don’t need to know how the music player decodes and plays the audio file. You just hear the music.
Understanding Class Variables in Python: Shared Attributes Across Instances
Class Variables: Class variables are attributes that are shared among all instances of a class. They are like a common property that every object of the class can access and modify.
Real-Life Example of Class Variables
Imagine you are in a classroom. The classroom has a whiteboard that
everyone can see and use. This whiteboard is like a class variable.
Explanation: “Imagine you are in a classroom. There
is a whiteboard that everyone in the class can see and write on. This
whiteboard is like a class variable in programming. It’s something
that everyone in the class shares.”
Python Code Example for Class Variables
class Classroom:
whiteboard = "This is a shared whiteboard." # Class variable
# Create two objects of the Classroom class
class1 = Classroom()
class2 = Classroom()
# Access the class variable
print(class1.whiteboard)
print(class2.whiteboard)
# Modify the class variable
Classroom.whiteboard = "The whiteboard has been updated."
# Access the modified class variable
print(class1.whiteboard)
print(class2.whiteboard)
In this example:
- whiteboard is a class variable shared by all instances of the Classroom class.
Understanding Instance Variables in Python: Unique Attributes for Each Instance
Instance Variables: Instance variables are attributes that are unique to each instance of a class. They are like personal properties that belong to each object.
Real-Life Example of Instance Variables
Imagine each student in the classroom has their own notebook. Each
notebook is unique to the student and contains their own notes. This
notebook is like an instance variable.
Explanation: “Imagine each student in the classroom
has their own notebook. Each notebook is unique to the student and
contains their own notes. This notebook is like an instance variable
in programming. It’s something that belongs to each student
individually.”
Python Code Example for Instance Variables
class Student:
def __init__(self, name):
self.name = name # Instance variable
# Create two objects of the Student class
student1 = Student("Alice")
student2 = Student("Bob")
# Access the instance variables
print(student1.name)
print(student2.name)
In this example:
- name is an instance variable unique to each Student object.
Real-Life Examples of Class and Instance Variables
-
Library System
- Class Variable: total_books (shared by all libraries)
- Instance Variable: books (unique to each library)
-
Car Dealership Network
- Class Variable: total_cars_sold (shared by all dealerships)
- Instance Variable: cars_in_stock (unique to each dealership)
-
Educational Institution
- Class Variable: school_name (shared by all students)
- Instance Variable: student_name (unique to each student)
-
Corporate Organization
- Class Variable: company_policy (shared by all employees)
- Instance Variable: employee_id (unique to each employee)
-
Sports Team
- Class Variable: team_name (shared by all players)
- Instance Variable: player_number (unique to each player)
Static and Class Methods in Python
Static methods and class methods are essential concepts in Python that offer different ways to interact with class data. Let’s dive into their definitions, uses, and real-life examples to understand them better.
What are Static Methods in Python?
Static Methods: Static methods are defined using the
@staticmethod
decorator. They do not require access to
the instance (self) or the class (cls). Essentially, they are regular
functions that belong to the class’s namespace.
Real-Life Example of Static Methods
Consider a calculator that can perform addition. You can use it to add numbers without needing to know anything about the calculator itself. This function of adding numbers is akin to a static method.
Python Code Example for Static Methods
class Calculator:
@staticmethod
def add(a, b):
return a + b
# Use the static method
result = Calculator.add(5, 3)
print(result) # Output: 8
In this example:
- add is a static method that adds two numbers and belongs to the Calculator class.
What are Class Methods in Python?
Class Methods: Class methods are defined using the
@classmethod
decorator. They take a reference to the
class (cls) as their first parameter and can modify class state that
applies across all instances of the class.
Real-Life Example of Class Methods
Imagine a school that can announce a holiday for all students. This announcement affects the entire class (school) and not just one student, similar to how a class method operates.
Python Code Example for Class Methods
class School:
school_name = "Greenwood High"
@classmethod
def change_school_name(cls, new_name):
cls.school_name = new_name
# Use the class method
School.change_school_name("Sunnydale High")
print(School.school_name) # Output: Sunnydale High
In this example:
- change_school_name is a class method that changes the name of the school for all instances of the School class.
Practical Examples of Static and Class Methods
-
Utility Functions in a Math Class
-
Static Method:
@staticmethod def calculate_area(radius):
(calculates the area of a circle) -
Class Method:
@classmethod def set_pi(cls, value):
(sets the value of π for all calculations)
-
Static Method:
-
Configuration Settings in an Application
-
Static Method:
@staticmethod def validate_config(config):
(validates a configuration file) -
Class Method:
@classmethod def update_config(cls, new_config):
(updates the configuration for the entire application)
-
Static Method:
-
Employee Management in a Company
-
Static Method:
@staticmethod def calculate_bonus(salary):
(calculates bonus based on salary) -
Class Method:
@classmethod def set_company_policy(cls, policy):
(sets a new company policy)
-
Static Method:
-
Game Development
-
Static Method:
@staticmethod def calculate_score(points):
(calculates the score based on points) -
Class Method:
@classmethod def set_difficulty_level(cls, level):
(sets the difficulty level for the game)
-
Static Method:
-
Library System
-
Static Method:
@staticmethod def is_valid_isbn(isbn):
(checks if an ISBN is valid) -
Class Method:
@classmethod def set_library_name(cls, name):
(sets the name of the library)
-
Static Method:
Operator Overloading in Python
Operator overloading allows you to define custom behavior for operators when they are used with objects of your class. This powerful feature enables you to make your classes more intuitive and easier to use.
What is Operator Overloading?
Operator Overloading: Operator overloading is the process of defining how operators (like +, -, *, etc.) work with user-defined objects. By overloading operators, you can specify custom behavior for these operators when they are used with instances of your class.
Deep Dive into Operator Overloading
Let’s take a closer look at how operator overloading works by exploring a detailed example with a custom Vector class.
Example: Overloading the + Operator for a Vector Class
Consider a Vector class that represents a vector in 2D space. We can overload the + operator to add two vectors together.
class Vector:
def __init__(self, x, y):
self.x = x
self.y = y
def __add__(self, other):
return Vector(self.x + other.x, self.y + other.y)
def __sub__(self, other):
return Vector(self.x - other.x, self.y - other.y)
def __mul__(self, scalar):
return Vector(self.x * scalar, self.y * scalar)
def __str__(self):
return f"Vector({self.x}, {self.y})"
# Create two Vector objects
v1 = Vector(2, 3)
v2 = Vector(4, 5)
# Use the overloaded + operator
v3 = v1 + v2
print(v3) # Output: Vector(6, 8)
# Use the overloaded - operator
v4 = v1 - v2
print(v4) # Output: Vector(-2, -2)
# Use the overloaded * operator
v5 = v1 * 3
print(v5) # Output: Vector(6, 9)
In this example:
- The __add__ method is overloaded to define how the + operator works with Vector objects.
- The __sub__ method is overloaded to define how the - operator works with Vector objects.
- The __mul__ method is overloaded to define how the * operator works with Vector objects and a scalar.
- The __str__ method provides a string representation of the Vector object for easy printing.
Practical Examples of Operator Overloading
-
Complex Numbers
- Class: ComplexNumber
- Overloaded Operators: +, -, *, /
- Explanation: Define how to add, subtract, multiply, and divide complex numbers.
class ComplexNumber: def __init__(self, real, imag): self.real = real self.imag = imag def __add__(self, other): return ComplexNumber(self.real + other.real, self.imag + other.imag) def __sub__(self, other): return ComplexNumber(self.real - other.real, self.imag - other.imag) def __mul__(self, other): return ComplexNumber(self.real * other.real - self.imag * other.imag, self.real * other.imag + self.imag * other.real) def __truediv__(self, other): denom = other.real ** 2 + other.imag ** 2 return ComplexNumber((self.real * other.real + self.imag * other.imag) / denom, (self.imag * other.real - self.real * other.imag) / denom) def __str__(self): return f"{self.real} + {self.imag}i" # Create two ComplexNumber objects c1 = ComplexNumber(1, 2) c2 = ComplexNumber(3, 4) # Use the overloaded operators print(c1 + c2) # Output: 4 + 6i print(c1 - c2) # Output: -2 + -2i print(c1 * c2) # Output: -5 + 10i print(c1 / c2) # Output: 0.44 + 0.08i
-
Fractions
- Class: Fraction
- Overloaded Operators: +, -, *, /
- Explanation: Define how to perform arithmetic operations with fractions.
from fractions import Fraction f1 = Fraction(1, 2) f2 = Fraction(3, 4) # Use the overloaded operators print(f1 + f2) # Output: 5/4 print(f1 - f2) # Output: -1/4 print(f1 * f2) # Output: 3/8 print(f1 / f2) # Output: 2/3
-
Matrices
- Class: Matrix
- Overloaded Operators: +, -, *
- Explanation: Define how to add, subtract, and multiply matrices.
class Matrix: def __init__(self, data): self.data = data def __add__(self, other): result = [[self.data[i][j] + other.data[i][j] for j in range(len(self.data[0]))] for i in range(len(self.data))] return Matrix(result) def __sub__(self, other): result = [[self.data[i][j] - other.data[i][j] for j in range(len(self.data[0]))] for i in range(len(self.data))] return Matrix(result) def __mul__(self, other): result = [[sum(a * b for a, b in zip(self_row, other_col)) for other_col in zip(*other.data)] for self_row in self.data] return Matrix(result) def __str__(self): return '\n'.join([' '.join(map(str, row)) for row in self.data]) # Create two Matrix objects m1 = Matrix([[1, 2], [3, 4]]) m2 = Matrix([[5, 6], [7, 8]]) # Use the overloaded operators print(m1 + m2) # Output: # 6 8 # 10 12 print(m1 - m2) # Output: # -4 -4 # -4 -4 print(m1 * m2) # Output: # 19 22 # 43 50
-
Points in 2D Space
- Class: Point
- Overloaded Operators: +, -
- Explanation: Define how to add and subtract points in a 2D space.
Sure, let's continue with the section on "Points in 2D Space": ```html class Point: def __init__(self, x, y): self.x = x self.y = y def __add__(self, other): return Point(self.x + other.x, self.y + other.y) def __sub__(self, other): return Point(self.x - other.x, self.y - other.y) def __str__(self): return f"Point({self.x}, {self.y})" # Create two Point objects p1 = Point(1, 2) p2 = Point(3, 4) # Use the overloaded operators print(p1 + p2) # Output: Point(4, 6) print(p1 - p2) # Output: Point(-2, -2)
Magic Methods in Python
Magic methods (also known as dunder methods) are special methods in Python that have double underscores at the beginning and end of their names. These methods allow you to define how objects of your class behave with built-in functions and operators.
What are Magic Methods?
Magic Methods: Magic methods are special methods that start and end with double underscores (__). They enable you to customize the behavior of your objects for built-in operations like printing, addition, and more.
Deep Dive into Common Magic Methods
Let’s explore some of the most commonly used magic methods with detailed examples.
1. __str__ and __repr__: String Representation of Objects
__str__: Defines the “informal” or nicely printable
string representation of an object, used by the
print()
function.
__repr__: Defines the “official” string
representation of an object, used by the repr()
function
and in the interactive interpreter.
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
def __str__(self):
return f"Person(name={self.name}, age={self.age})"
def __repr__(self):
return f"Person('{self.name}', {self.age})"
# Create a Person object
p = Person("Alice", 30)
# Use the __str__ and __repr__ methods
print(str(p)) # Output: Person(name=Alice, age=30)
print(repr(p)) # Output: Person('Alice', 30)
2. __add__: Overloading the Addition Operator
__add__: Defines the behavior of the + operator for objects of your class.
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
def __add__(self, other):
return Point(self.x + other.x, self.y + other.y)
def __str__(self):
return f"Point({self.x}, {self.y})"
# Create two Point objects
p1 = Point(1, 2)
p2 = Point(3, 4)
# Use the overloaded + operator
p3 = p1 + p2
print(p3) # Output: Point(4, 6)
3. __len__: Defining the Length of an Object
__len__: Defines the behavior of the
len()
function for objects of your class.
class CustomList:
def __init__(self, items):
self.items = items
def __len__(self):
return len(self.items)
# Create a CustomList object
cl = CustomList([1, 2, 3, 4, 5])
# Use the len() function
print(len(cl)) # Output: 5
4. __getitem__ and __setitem__: Indexing and Assignment
__getitem__: Defines the behavior of indexing
(obj[key]
) for objects of your class.
__setitem__: Defines the behavior of item assignment
(obj[key] = value
) for objects of your class.
class CustomDict:
def __init__(self):
self.data = {}
def __getitem__(self, key):
return self.data[key]
def __setitem__(self, key, value):
self.data[key] = value
# Create a CustomDict object
cd = CustomDict()
# Use the __setitem__ and __getitem__ methods
cd['name'] = 'Alice'
print(cd['name']) # Output: Alice
5. __call__: Making an Object Callable
__call__: Defines the behavior of calling an object as a function.
class Multiplier:
def __init__(self, factor):
self.factor = factor
def __call__(self, value):
return value * self.factor
# Create a Multiplier object
double = Multiplier(2)
# Use the object as a function
print(double(5)) # Output: 10
Practical Examples of Magic Methods
-
Custom Container Class
- Magic Methods: __len__, __getitem__, __setitem__, __delitem__
- Explanation: Define how to get the length, access items, set items, and delete items in a custom container.
class CustomContainer: def __init__(self): self.data = [] def __len__(self): return len(self.data) def __getitem__(self, index): return self.data[index] def __setitem__(self, index, value): self.data[index] = value def __delitem__(self, index): del self.data[index] # Create a CustomContainer object cc = CustomContainer() cc.data = [1, 2, 3, 4, 5] # Use the magic methods print(len(cc)) # Output: 5 print(cc[2]) # Output: 3 cc[2] = 10 print(cc[2]) # Output: 10 del cc[2] print(cc.data) # Output: [1, 2, 4, 5]
-
Custom Numeric Class
- Magic Methods: __add__, __sub__, __mul__, __truediv__
- Explanation: Define how to add, subtract, multiply, and divide custom numeric objects.
class CustomIterator: def __init__(self, start, end): self.current = start self.end = end def __iter__(self): return self def __next__(self): if self.current >= self.end: raise StopIteration self.current += 1 return self.current - 1 # Create a CustomIterator object ci = CustomIterator(1, 5) # Use the iterator for num in ci: print(num) # Output: 1 2 3 4
Property Decorators in Python
Property decorators in Python provide a way to manage the attributes of a class by defining getters, setters, and deleters. This allows for controlled access to private attributes and can help in maintaining encapsulation.
What are Property Decorators?
Property Decorators: Property decorators are used to
define methods in a class that act as getters, setters, and deleters
for an attribute. The @property
decorator is used for the
getter method, @.setter
for the setter method, and
@.deleter
for the deleter method.
Deep Dive into Property Decorators
Let’s explore how property decorators work with detailed examples.
Example: Using @property for Getters
The @property
decorator allows you to define a method
that gets called automatically when you access an attribute.
class Circle:
def __init__(self, radius):
self._radius = radius
@property
def radius(self):
return self._radius
# Create a Circle object
c = Circle(5)
# Access the radius property
print(c.radius) # Output: 5
In this example:
-
The radius method is decorated with
@property
, making it a getter for the _radius attribute.
Example: Using @.setter for Setters
The @.setter
decorator allows you to define a method that
gets called automatically when you set an attribute.
class Circle:
def __init__(self, radius):
self._radius = radius
@property
def radius(self):
return self._radius
@radius.setter
def radius(self, value):
if value < 0:
raise ValueError("Radius cannot be negative")
self._radius = value
# Create a Circle object
c = Circle(5)
# Set the radius property
c.radius = 10
print(c.radius) # Output: 10
# Attempt to set a negative radius
try:
c.radius = -5
except ValueError as e:
print(e) # Output: Radius cannot be negative
In this example:
-
The radius method is decorated with
@property
to act as a getter. -
The radius method is also decorated with
@radius.setter
to act as a setter, which includes validation to prevent negative values.
Example: Using @.deleter for Deleters
The @.deleter
decorator allows you to define a method
that gets called automatically when you delete an attribute.
class Circle:
def __init__(self, radius):
self._radius = radius
@property
def radius(self):
return self._radius
@radius.setter
def radius(self, value):
if value < 0:
raise ValueError("Radius cannot be negative")
self._radius = value
@radius.deleter
def radius(self):
print("Deleting radius")
del self._radius
# Create a Circle object
c = Circle(5)
# Delete the radius property
del c.radius
In this example:
-
The radius method is decorated with
@property
to act as a getter. -
The radius method is also decorated with
@radius.setter
to act as a setter. -
The radius method is further decorated with
@radius.deleter
to act as a deleter, which prints a message and deletes the _radius attribute.
Practical Examples of Property Decorators
-
Temperature Conversion
- Class: Temperature
- Properties: celsius, fahrenheit
- Explanation: Use property decorators to convert between Celsius and Fahrenheit.
class Temperature: def __init__(self, celsius): self._celsius = celsius @property def celsius(self): return self._celsius @celsius.setter def celsius(self, value): self._celsius = value @property def fahrenheit(self): return (self._celsius * 9/5) + 32 @fahrenheit.setter def fahrenheit(self, value): self._celsius = (value - 32) * 5/9 # Create a Temperature object temp = Temperature(25) # Access and set properties print(temp.celsius) # Output: 25 print(temp.fahrenheit) # Output: 77.0 temp.fahrenheit = 100 print(temp.celsius) # Output: 37.77777777777778
-
Bank Account Balance
- Class: BankAccount
- Properties: balance
- Explanation: Use property decorators to manage the balance with validation.
class BankAccount: def __init__(self, balance): self._balance = balance @property def balance(self): return self._balance @balance.setter def balance(self, value): if value < 0: raise ValueError("Balance cannot be negative") self._balance = value # Create a BankAccount object account = BankAccount(1000) # Access and set properties print(account.balance) # Output: 1000 account.balance = 1500 print(account.balance) # Output: 1500 try: account.balance = -500 except ValueError as e: print(e) # Output: Balance cannot be negative
-
Rectangle Area and Perimeter
- Class: Rectangle
- Properties: width, height, area, perimeter
- Explanation: Use property decorators to calculate area and perimeter.
class Rectangle: def __init__(self, width, height): self._width = width self._height = height @property def width(self): return self._width @width.setter def width(self, value): if value < 0: raise ValueError("Width cannot be negative") self._width = value @property def height(self): return self._height @height.setter def height(self, value): if value < 0: raise ValueError("Height cannot be negative") self._height = value @property def area(self): return self._width * self._height @property def perimeter(self): return 2 * (self._width + self._height) # Create a Rectangle object rect = Rectangle(4, 5) # Access properties print(rect.area) # Output: 20 print(rect.perimeter) # Output: 18 # Set properties rect.width = 6 print(rect.area) # Output: 30
-
Employee Salary
- Class: Employee
- Properties: salary, bonus
- Explanation: Use property decorators to manage salary and calculate bonus.
class Employee: def __init__(self, salary): self._salary = salary @property def salary(self): return self._salary @salary.setter def salary(self, value): if value < 0: raise ValueError("Salary cannot be negative") self._salary = value @property def bonus(self): return self._salary * 0.1 # Create an Employee object emp = Employee(50000) # Access properties print(emp.salary) # Output: 50000 print(emp.bonus) # Output: 5000.0 # Set properties emp.salary = 60000 print(emp.bonus) # Output: 6000.0