Article Categories
- All Categories
-
Data Structure
-
Networking
-
RDBMS
-
Operating System
-
Java
-
MS Excel
-
iOS
-
HTML
-
CSS
-
Android
-
Python
-
C Programming
-
C++
-
C#
-
MongoDB
-
MySQL
-
Javascript
-
PHP
-
Economics & Finance
How can a Python subclass control what data is stored in an immutable instance?
When subclassing an immutable type like int, str, or tuple, you need to override the __new__() method instead of __init__() to control what data gets stored in the instance.
The __new__ method gets called when an object is created, whereas __init__() initializes the object after creation. For immutable types, the data must be set during object creation, not initialization.
Understanding Magic Methods
Magic methods (also called dunder methods) are identified by double underscores as prefix and suffix. They allow us to customize object behavior in Python ?
print(dir(int))
['__abs__', '__add__', '__and__', '__bool__', '__ceil__', '__class__', '__delattr__', '__dir__', '__divmod__', '__doc__', '__eq__', '__float__', '__floor__', '__floordiv__', '__format__', '__ge__', '__getattribute__', '__getnewargs__', '__gt__', '__hash__', '__index__', '__init__', '__init_subclass__', '__int__', '__invert__', '__le__', '__lshift__', '__lt__', '__mod__', '__mul__', '__ne__', '__neg__', '__new__', '__or__', '__pos__', '__pow__', '__radd__', '__rand__', '__rdivmod__', '__reduce__', '__reduce_ex__', '__repr__', '__rfloordiv__', '__rlshift__', '__rmod__', '__rmul__', '__ror__', '__round__', '__rpow__', '__rrshift__', '__rshift__', '__rsub__', '__rtruediv__', '__rxor__', '__setattr__', '__sizeof__', '__str__', '__sub__', '__subclasshook__', '__truediv__', '__trunc__', '__xor__', 'as_integer_ratio', 'bit_length', 'conjugate', 'denominator', 'from_bytes', 'imag', 'numerator', 'real', 'to_bytes']
The __init__() Method Example
Here's how __init__() works with mutable objects ?
class String:
# The magic method to initiate object
def __init__(self, string):
self.string = string
# Driver Code
if __name__ == '__main__':
# object creation
myStr = String('Demo')
# print object location
print(myStr)
<__main__.String object at 0x7f34c97799d0>
Subclassing Immutable Types with __new__()
To control data in immutable instances, override __new__() method. Here are three practical examples ?
from datetime import date
class FirstOfMonthDate(date):
"Always choose the first day of the month"
def __new__(cls, year, month, day):
return super().__new__(cls, year, month, 1)
class NamedInt(int):
"Allow text names for some numbers"
xlat = {'zero': 0, 'one': 1, 'ten': 10, 'fifteen': 15}
def __new__(cls, value):
value = cls.xlat.get(value, value)
return super().__new__(cls, value)
class TitleStr(str):
"Convert str to name suitable for a URL path"
def __new__(cls, s):
s = s.lower().replace(' ', '-')
s = ''.join([c for c in s if c.isalnum() or c == '-'])
return super().__new__(cls, s)
# Testing the subclasses
print(FirstOfMonthDate(2022, 9, 8))
print(NamedInt('fifteen'))
print(NamedInt(18))
# Create a URL path
print(TitleStr('course for beginners'))
2022-09-01 15 18 course-for-beginners
How It Works
FirstOfMonthDate: Forces any date to use day 1, regardless of the input day.
NamedInt: Translates string names to integers using a lookup dictionary.
TitleStr: Converts text to URL-friendly format by lowercasing, replacing spaces with hyphens, and removing special characters.
Key Points
? Use __new__() for immutable types because data must be set at creation time
? Use __init__() for mutable types to initialize after creation
? Always call super().__new__() with modified data to create the instance
Conclusion
Override __new__() when subclassing immutable types to control the data stored in instances. This allows you to create specialized versions of built-in immutable types with custom behavior while maintaining their immutable nature.
