In Python, every class implicit inherits from the object class if no explicit parent class is specified. This makes object the foundational class for all others—ensuring that every instance gains access to its methods and attributes.
Key Methods in the object Class
__new__(): Invoked by the system to allocate memory and create a new instance.__init__(): Called manually after object creation to initialize instance variables.__str__(): Defines how an object is represented as a string; returns a string value (default is the memory address).
Use dir() to inspect all attributes and methods available on an instance:
class Person:
def __init__(self, full_name, years):
self.name = full_name
self.age = years
def introduce(self):
print(f'Hello, I am {self.name}, aged {self.age}.')
# Instantiate the class
person = Person('Sam', 15)
print(dir(person))
The output includes both user-defined members (e.g., name, age, introduce) and inherited ones from object. The latter are automatically available across all objects.
Overloading Operators via Special Methods
Python allows custom behavior for built-in operators through special method overrides:
| Operator | Method | Purpose |
|---|---|---|
| + | __add__() |
Addition |
| - | __sub__() |
Subtraction |
| < | __lt__() |
Less than |
| <= | __le__() |
Less than or equal |
| == | __eq__() |
Equlaity |
| > | __gt__() |
Greater than |
| >= | __ge__() |
Greater than or equal |
| != | __ne__() |
Inequality |
| * | __mul__() |
Multiplication |
| / | __truediv__() |
True division |
| % | __mod__() |
Modulo |
| // | __floordiv__() |
Floor division |
| ** | __pow__() |
Power |
Example usage:
x = 10
y = 20
print(x.__add__(y)) # Output: 30
print(x.__sub__(y)) # Output: -10
print('x < y:', x.__lt__(y)) # Output: True
print('x <= y:', x.__le__(y)) # Output: True
Important Built-in Attributes
These attributes provide introspection capabilities for classes and instances:
| Attribute | Description |
|---|---|
obj.__dict__ |
Dictionary containing the instance’s attributes |
obj.__class__ |
The class to which the instance belongs |
cls.__bases__ |
Tuple of direct parent classes |
cls.__base__ |
First parent class in inheritance hierarchy |
cls.__mro__ |
Method Resolution Order – list of classes in search path |
cls.__subclasses__() |
List of subclasses defined direct under this class |
Demonstration:
class A:
pass
class B:
pass
class C(A, B):
def __init__(self, name, age):
self.name = name
self.age = age
inst_a = A()
inst_b = B()
inst_c = C('sam', 15)
# Inspect instance data
print('A instance attrs:', inst_a.__dict__) # {}
print('B instance attrs:', inst_b.__dict__) # {}
print('C instance attrs:', inst_c.__dict__) # {'name': 'sam', 'age': 15}
print('-' * 50)
# Check class membership
print('A type:', inst_a.__class__) # <class '__main__.A'>
print('B type:', inst_b.__class__) # <class '__main__.B'>
print('C type:', inst_c.__class__) # <class '__main__.C'>
print('-' * 50)
# Parent class information
print('A parents:', A.__bases__) # (<class 'object'>,)
print('B parents:', B.__bases__) # (<class 'object'>,)
print('C parents:', C.__bases__) # (<class '__main__.A'>, <class '__main__.B'>)
print('-' * 50)
# Direct base
print('A base:', A.__base__) # <class 'object'>
print('B base:', B.__base__) # <class 'object'>
print('C base:', C.__base__) # <class '__main__.A'>
print('-' * 50)
# Method resolution order
print('A MRO:', A.__mro__) # (<class '__main__.A'>, <class 'object'>)
print('B MRO:', B.__mro__) # (<class '__main__.B'>, <class 'object'>)
print('C MRO:', C.__mro__) # (<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>, <class 'object'>)
print('-' * 50)
# Subclasses
print('A subclasses:', A.__subclasses__()) # [<class '__main__.C'>]
print('B subclasses:', B.__subclasses__()) # [<class '__main__.C'>]
print('C subclasses:', C.__subclasses__()) # []
This reveals how Python’s object model enables deep inspection and dynamic control over class hierarchies and object behavior.