Loading Page Content...
Preparing courses, live labs, and learning resources.सामग्री लोड हो रही है, कृपया प्रतीक्षा करें...
Preparing courses, live labs, and learning resources.सामग्री लोड हो रही है, कृपया प्रतीक्षा करें...
Beyond basic arithmetic and string representations, Python's Data Model enables deep customization of user-defined classes. By implementing container protocols, callable behaviors, and attribute access hooks, you can create objects that behave like custom dictionaries, custom lists, dynamic proxies, or stateful function pipelines.
In Python, an object becomes a collection or container by implementing the Sequence Protocol or Mapping Protocol:
| Operation | Dunder Method | Example Syntax |
|---|---|---|
| Read element | __getitem__(self, key) | val = container[key] or container[start:stop] |
| Assign element | __setitem__(self, key, value) | container[key] = value |
| Delete element | __delitem__(self, key) | del container[key] |
| Membership check | __contains__(self, item) | if item in container: |
| Length count | __len__(self) | total = len(container) |
__getitem__When an indexing expression includes colons (e.g. obj[1:5:2]), Python constructs a built-in slice object and passes it to __getitem__.
__call__ MethodBy implementing __call__(self, *args, **kwargs), an instance can be invoked directly with parentheses obj(), behaving like a function while maintaining persistent internal state.
__getattr__ vs __getattribute__Python provides distinct hooks for intercepting attribute access:
__getattribute__(self, name): Intercepts every single attribute access unconditionally. Modifying this requires extreme caution to avoid infinite recursion.__getattr__(self, name): The graceful fallback. It is only called if the attribute was NOT found in normal dictionary lookup.| Method | Trigger Syntax | Critical Caveat |
|---|---|---|
__getitem__ | obj[key] | Must handle slice objects if sequence behavior is expected. |
__setitem__ | obj[key] = val | Should validate keys according to container domain rules. |
__contains__ | item in obj | Must return a boolean. If omitted, Python falls back to iterating with __iter__. |
__call__ | obj(*args) | Makes callable(obj) == True. Ideal for stateful closures and middleware. |
__getattr__ | obj.attr | Fallback only; runs only when normal lookup fails. |
__getattribute__ | obj.attr | Always runs. Must use super().__getattribute__ to avoid infinite recursion. |
__eq__ Without __hash__Defining __eq__ automatically sets __hash__ = None, making your class unhashable (it cannot be stored in sets or used as dictionary keys). If instances are immutable, explicitly implement __hash__.
__getitem__When creating a custom sequence class, obj[1:4] passes a slice object to __getitem__, not an integer. Always check if isinstance(index, slice):.
Implement a callable Multiplier class using __call__ that allows instances of the class to be invoked directly like regular functions.
Which dunder method is executed when an element is retrieved via square bracket notation value = obj["my_key"]? A. __get__ B. __getattr__ C. __getitem__ D. __access__
obj[key] is mapped directly to __getitem__(self, key).What object type does Python pass as the key argument to __getitem__ when an expression like obj[2:10:2] is executed? A. A tuple containing (2, 10, 2) B. A built-in slice object with start=2, stop=10, step=2 C. A range object range(2, 10, 2) D. A string "2:10:2"
slice(2, 10, 2) instance and passes it directly to __getitem__ when colon slicing syntax is used.What built-in function returns True when evaluated on an instance whose class defines the __call__ method? A. isfunction() B. callable() C. hasattr() D. isinstance(obj, FunctionType)
callable(obj) returns True for any object whose class implements the __call__ dunder method.What is the key difference between __getattr__ and __getattribute__? A. __getattr__ is called on every attribute access, while __getattribute__ is only a fallback. B. __getattribute__ is called unconditionally on every attribute lookup, while __getattr__ is only called if standard attribute resolution fails. C. __getattr__ is private, whereas __getattribute__ is public. D. __getattribute__ is deprecated in Python 3.
__getattribute__ intercepts every attribute access unconditionally. __getattr__ is only invoked as a fallback mechanism when the attribute is not found in the object's instance dictionary or class hierarchy.Inside __getattribute__, how should you safely access attributes on the instance without triggering infinite recursion? A. Directly access self.__dict__[name] B. Call self.name C. Delegate via super().__getattribute__(name) or object.__getattribute__(self, name) D. Call getattr(self, name)
self.__dict__ or calling getattr(self, ...) inside __getattribute__ triggers __getattribute__ again, causing infinite recursion and a RecursionError. One must use super().__getattribute__(name).In the next lesson, we will continue your advanced Python journey with Project: Vector Class with Overloaded Operators (2: Magic Methods & Operator Overloading).
👉 Continue to Next Lesson: Project: Vector Class with Overloaded Operators →
Continue learning with hands-on practice, examples, and exercises in the upcoming topic.
| Previous Lesson | Next Lesson |
|---|---|
| Operator Overloading | CPython Internals: Memory Management, Garbage Collection, and __slots__ |
Test your understanding of this lesson with 5 questions. Each question has one correct answer.