0% found this document useful (0 votes)
2 views43 pages

Week 3b - Python Special Methods

This document provides an overview of special methods (magic or dunder methods) in Python, which allow custom objects to interact with built-in operations and behave like native types. It covers various special methods such as __init__(), __str__(), __len__(), __eq__(), and operator overloading methods, explaining their purpose and providing examples. Additionally, it includes a lab session task to implement special methods in a ShoppingCart class.
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
2 views43 pages

Week 3b - Python Special Methods

This document provides an overview of special methods (magic or dunder methods) in Python, which allow custom objects to interact with built-in operations and behave like native types. It covers various special methods such as __init__(), __str__(), __len__(), __eq__(), and operator overloading methods, explaining their purpose and providing examples. Additionally, it includes a lab session task to implement special methods in a ShoppingCart class.
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd

WEEK 3b

EL 162 / 234 OBJECT ORIENTED


PROGRAMMING
By: Dr. Matthew Cobbinah

mcobbinah@[Link] | 0547900989
Objectives

At the end of this lecture, students should be able to:


• Work with Special Methods as one of the goals of OOP
✓ Hide implementation details and expose a simple interface.
Special Methods
(Magic/Dunder)
SPECIAL METHODS

What are Special Methods?


• Predefined methods that begin and end with double underscores.
• They are also called magic or dunder (short for Double UNDERscore) methods
• They allow Python objects to respond to built-in operations in simple ways
• Special methods are not a separate method type.
✓ They can be instance methods, class-oriented methods, or methods that operate
before an instance exists.
✓ What makes them "special" is not their parameter list, but that Python
automatically invokes them in response to language syntax and built-in
operations.

For example:
• len(obj) internally calls obj.__len__()
• obj1 == obj2 calls obj1.__eq__(obj2)
SPECIAL METHODS…
• Special methods allow your objects to behave like built-in types.
• So special methods are not duplicates of built-in functions.
• They are the mechanism by which custom objects teach Python how to apply built-in
operations to them.
• That is why they are fundamental to making user-defined classes feel like native
Python types.
Example:
• Python already has the + operator, so 3+7, will give you 10
• However, if these values are object data, you would have to teach Python how it
should apply the add (+) inbuilt method on the objects
• So you define:
def __add__(self, other):
return addnumbers([Link] + [Link])
• Now Python can interpret:
num1 + num2
Common Examples of Special Methods

1. Constructor __init__()
2. string representation __str__(), __repr__()
3. length __len__()
4. equality __eq__()
5. operator overloading ___add()__ , __sub__(), __mul()
6. item access __getitem__()
7. item assignment __setitem__()
8. membership testing __contains__()
9. callable objects __call__()
[Link] support __iter__(), __next__()
[Link] evaluation __bool__()
[Link] __del__()
1. Constructors in Python (__init__)
• A constructor is a special method in Python called automatically every time a class is
being used to create a new object.
• It is used to initialize the attributes of an object.
• Without a constructor, every attribute would have to be assigned manually after
object creation, which is inefficient and error-prone.

Key Points
✓ Named __init__
✓ Runs automatically during object creation
✓ Uses self to refer to the current object
✓ Ensures objects start in a valid state

Purpose
✓ Assign initial values to object attributes
✓ Prepare the object for use immediately after creation
1. Constructors in Python (__init__)…
• Constructor Example 1:
class Student:
def __init__(self, name, age):
[Link] = name
[Link] = age

s1 = Student("Matthew", 30)

print([Link])
print([Link])

When Python executes Student("Matthew", 30), it automatically calls, s1.__init__("Matthew", 30)


1. Constructors in Python (__init__)…
• Constructor Example 2:
class Book:
def __init__(self, title, author):
[Link] = title
[Link] = author

def describe(self):
print(f"{[Link]} by {[Link]}")

b1 = Book("OOP", "Dr. Cobbinah")


[Link]()
2. String Representation Methods
• Python provides two major string representation methods.
✓ Informal Representation: __str__()
✓ Formal Representation: __repr__()
2.1 Informal Representation: __str__()
• The __str__() method provides a human-readable representation of an object.
• It defines what should be displayed when an object is printed.
• Without this method, Python displays the object's memory location, which is not
useful to users.
• This method is intended for end users rather than developers.

Syntax
def __str__(self):
return string
2.1 Informal Representation: __str__()
# Example:
class Student:
def __init__(self, name):
[Link] = name

def __str__(self):
return f"Student: {[Link]}"

s = Student("Matthew")
print(s)

#Output
Student: Matthew
__str__() controls how users see an object.
2.2 Formal String Representation ( __repr__() )
• The __repr__() method provides an official or developer-oriented representation of an
object.
• It is primarily used for debugging and logging.
• Ideally, the returned string should contain enough information to recreate the object.
• When __str__() is not defined, Python falls back to __repr__().

Syntax
def __repr__(self):
return string
2.2 Formal String Representation ( __repr__() )
# Example
class Student:
def __init__(self, name):
[Link] = name

def __repr__(self):
return f"Student('{[Link]}')"

s = Student(“Daniella")
print(repr(s))

#Output
Student(‘Daniella')
__repr__() is aimed at developers; __str__() is aimed at users.
Difference Between __str__() and __repr__()
class Student:
def __init__(self, name):
[Link] = name

def __str__(self):
return f"Name: {[Link]}"

def __repr__(self):
return f"Student('{[Link]}')"

s = Student("Matthew")
print(s)
print(repr(s))

#Output:
Name: Matthew
Student('Matthew')
3. Length Method: __len__()
• The __len__() method allows custom objects to define what their length means.
• Python's built-in collections such as lists, tuples, dictionaries, and strings all implement
this method.
• By implementing __len__(), custom objects can work naturally with the built-in len()
function.

Syntax
def __len__(self):
return integer
3. Length Method: __len__()

# Example:
class Playlist:
def __init__(self, songs):
[Link] = songs

def __len__(self):
return len([Link])

p = Playlist(["Song1", "Song2", "Song3"])

print(len(p))

A call to len(p) means Python internally calls the p.__len__()


4. Equality Comparison: __eq__()
• The __eq__() method defines how objects should be compared for equality.
• By default, Python compares whether two variables refer to the same memory
location.
• Many applications, however, require comparison based on object content rather than
identity.
• When we call object1 == object2, internally, Python does this
object1.__eq__(object2)

Syntax
def __eq__(self, other):
return boolean
4. Equality Comparison: __eq__()

# Example
class Student:
def __init__(self, student_id):
self.student_id = student_id

def __eq__(self, other):


return self.student_id == other.student_id

s1 = Student(101)
s2 = Student(101)

print(s1 == s2)

Without __eq__, Python would compare memory addresses instead.


5. Operator Overloading
• Operator overloading allows programmers to define how operators behave when
applied to custom objects.
• Allows operators to work with custom objects.
• This enables objects to behave naturally and intuitively.
• For example, adding two vectors should produce another vector rather than raising an
error.

When is it called?
Syntax
obj1 + obj2
def __add__(self, other):
Internally:
...
obj1.__add__(obj2)
5.1 Addition: __add__()
# Example
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 __str__(self):
return f"({self.x}, {self.y})"

v1 = Vector(2, 3)
v2 = Vector(4, 5)

print(v1 + v2)
5.2 Subtraction: __sub__()

class Vector:
def __init__(self, x):
self.x = x

def __sub__(self, other):


return Vector(self.x - other.x)

def __str__(self):
return str(self.x)

v1 = Vector(10)
v2 = Vector(3)

print(v1 - v2)

#Output:
7
5.3 Multiplication: __mul__()
class Number:
def __init__(self, value):
[Link] = value

def __mul__(self, other):


return Number([Link] * [Link])

def __str__(self):
return str([Link])

n1 = Number(5)
n2 = Number(4)

print(n1 * n2)

#Output:
20
Common Operator Overloading Methods

Operator Method
+ __add__
- __sub__
* __mul__
/ __truediv__
// __floordiv__
% __mod__
** __pow__
== __eq__
!= __ne__
< __lt__
<= __le__
> __gt__
>= __ge__
6. Item Access: __getitem__()
• The __getitem__() method enables an object to behave like a sequence or container.
• It allows elements to be accessed using indexing notation, just like lists and tuples.
• Implementing this method makes custom objects more intuitive and compatible with
Python's indexing syntax.

Syntax
def __getitem__(self, index):
...
6. Item Access: __getitem__()
# Example
class Grades:
def __init__(self):
[Link] = [85, 90, 78]

def __getitem__(self, index):


return [Link][index]

g = Grades()

print(g[0])
print(g[1])

Python internally executes: g.__getitem__(0)


7. Item Assignment: __setitem__()
• The __setitem__() method enables assignment using indexing notation.
✓ It allows assignment using indexing.
• It allows objects to store or modify values in a way similar to lists and dictionaries.
• This method is commonly used when building custom container classes.

When is it called?
object[index] = value
Internally:
object.__setitem__(index, value)
7. Item Assignment: __setitem__()
# Example
class Grades:
def __init__(self):
[Link] = [85, 90, 78]

def __setitem__(self, index, value):


[Link][index] = value

g = Grades()
g[1] = 100

print([Link])
#Output: [85, 100, 78]
8. Membership Testing: __contains__()
• The __contains__() method defines membership testing for custom objects.
• It determines how the in operator behaves.
• This is useful when an object manages a collection of elements and should support
membership queries

When is it called?
item in object
Internally: object.__contains__(item)
8. Membership Testing: __contains__()…
# Example
class Course:
def __init__(self):
[Link] = [“Ella", “Sandra", “Joe"]

def __contains__(self, student):


return student in [Link]

c = Course()
print(“Joe" in c)
print(“Gifty" in c)

#Output:
True
False
9. Callable Objects: __call__()
• The __call__() method allows an object to be invoked (or behave) like a function.
• This is useful when objects need to maintain internal state while still behaving like
callable functions.
• Many advanced Python frameworks use callable objects extensively.

When is it called?
object(arguments)
Internally:
object.__call__(arguments)
9. Callable Objects: __call__()

# Example
class Multiplier:
def __init__(self, factor):
[Link] = factor

def __call__(self, number):


return number * [Link]

double = Multiplier(2)
print(double(10)) #double now behaves like a function

#Output:
20
10. Iteration Support: __iter__() and __next__()
• These methods allow objects to work in loops/iteration.
• Together they form the foundation of Python's iterator protocol, which powers for
loops.
• An iterator must know how to provide the next value and when iteration should stop.

When are they called?


for item in object:
...
Python repeatedly calls:
__iter__()
__next__()
until a StopIteration exception is raised.
10. Iteration Support: __iter__() and __next__()
# Example
class Counter:
def __init__(self, limit):
[Link] = limit
[Link] = 1

def __iter__(self):
return self
Output:
def __next__(self): 1
if [Link] > [Link]: 2
raise StopIteration
3
value = [Link]
[Link] += 1 4
return value

for num in Counter(5):


print(num)
11. Boolean Evaluation: __bool__()
• The __bool__() method determines how an object behaves in Boolean contexts.
• It basically controls truth-value testing.
• It allows objects to define what should be considered True or False.
• This method is commonly used in classes representing states, conditions, or resources.

When is it called?
if object:
or
bool(object)
11. Boolean Evaluation: __bool__()
# Example
class BankAccount:
def __init__(self, balance):
[Link] = balance

def __bool__(self):
return [Link] > 0

account = BankAccount(500)

if account:
print("Account is active")

#Output:
Account is active
12. Destructor Method: __del__()
• The __del__() method is known as the destructor.
• It is called/executed when an object is about to be removed from memory or when an
object is being destroyed.
• Historically it was used for resource cleanup such as closing files or releasing network
connections.
• However, because Python's garbage collection timing is not always predictable,
modern Python programs generally prefer context managers (with statements) for
cleanup tasks.
✓ Avoid relying on __del__() for critical cleanup operations.

Syntax
def __del__(self):
...
12. Destructor Method: __del__()

# Example 1:
class FileHandler:

def __init__(self, filename):


[Link] = filename
print("File opened")

def __del__(self):
print("File closed")

f = FileHandler("[Link]")
12. Destructor Method: __del__()

# Example 2
class Resource:
def __init__(self):
print("Resource allocated")

def __del__(self):
print("Resource released")

r = Resource()
Special Methods in Summary

Special Method Purpose


__init__ Initialize object
__str__ User-friendly string
__repr__ Developer/debug representation
__len__ Define object length
__eq__ Equality comparison
__lt__, __gt__,
etc. Relational comparisons
__add__, __sub__, __mul__ Operator overloading
__getitem__ Index access
__setitem__ Index assignment
__contains__ Membership testing
__iter__ Create iterator
__next__ Return next item
__call__ Make object callable
__bool__ Truth-value testing
__del__ Destructor
LAB Session
WEEK 3b - Complete the ShoppingCart class by implementing the
required special methods.
class ShoppingCart:
def __init__(self, items):
pass # Test Code
cart1 = ShoppingCart(["Laptop", "Mouse", "Keyboard"])
def __str__(self): cart2 = ShoppingCart(["Laptop", "Mouse", "Keyboard"])
pass
print(cart1) # String representation
def __len__(self): print(len(cart1)) # Number of items
pass print(cart1[0]) # Access first item

def __getitem__(self, index): cart1[1] = "Headset" # Modify second item


pass
print(cart1)
def __setitem__(self, index, value): print(cart1 == cart2) # Compare carts
pass
# Challenge
def __eq__(self, other): cart3 = cart1 + cart2
pass print(cart3)

# Challenge Shopping Cart: ['Laptop', 'Mouse', 'Keyboard']


def __add__(self, other): 3
Laptop
pass
Expected Output Shopping Cart: ['Laptop', 'Headset', 'Keyboard']
False
Shopping Cart: ['Laptop', 'Headset', 'Keyboard',
'Laptop', 'Mouse', 'Keyboard']
Week 3b — Key Takeaways

4. Custom behavior for user-defined


1. Python Special Methods
types

2. Cleaner code 5. Operator overloading

3. Integration with built-in functions 6. ShoppingCart class with special


methods

You might also like