Python Object Method¶
There are some methods, you may have heard of, but rarely used them, especially those start and end with __
.
In this tutorial, we will explore some of them.
Basic¶
Create¶
__new__
and __init__
are called upon creation and initialization of an instance.
__new__
and __init__
__new__(cls)
will return an instance or a subclass of the class, and if the class of the instance returned is the same as the class cls
, __init__
will be called, otherwise not.
Let's have a look at the codes below to understand this behaviour.
class UnderneathAll:
author = 'underneath-all'
@classmethod
def __new__(cls, *args, **kwargs):
print('__new__ entered')
return super().__new__(cls)
def __init__(self, *args, **kwargs):
print('__init__ entered')
return super().__init__()
class UnderneathAllDict:
author = 'underneath-all'
@classmethod
def __new__(cls, *args, **kwargs):
print('__new__ entered')
return dict()
def __init__(self, *args, **kwargs):
print('__init__ entered')
return super().__init__()
Run
ua = UnderneathAll()
Output
__new__ entered
__init__ entered
Run
ua_dict = UnderneathAllDict()
Output
__new__ entered
Tips
I think you might have noticed. You can override __new__
and __init__
methods to manipulate the behavior of creating and initializing an instance.
You can even return an instance of a different class. It is quite useful when you need to maintain the compatibility of current codes while adding some new features.
However, do keep in mind: __init__
method may not always get called after __new__
. This is a common mistake I've seen in some codes, they assume the __init__
will be called even after they override the __new__
method.
Call¶
Delete¶
__delete__
method is called when an object is going to be destroyed.
However, keep in mind, python tracks objects using reference count. Even if you delete an instance, if the instance has other reference pointing at it, it won't be destroyed and the __del__
method won't be called.
Tips
Python uses a reference counting mechanism to track objects. When the reference count of an object is 0, the object will be garbage collected.
__del__
class UnderneathAll:
def __del__(self):
print('deleting')
return True
ua_del = UnderneathAll()
del ua_del
Output
deleting
Read¶
iter¶
__iter__
method is responsible for iterating the object. It is not quite straight forward, let define a class similar to range
to help you understand.
iter"
import operator
class UnderneathAllRange:
def __init__(self, start, end, step=1):
if (end - start) * step < 0 or step == 0:
raise Exception("Incorrect step value")
self.step = step
self.start = start
self.end = end
self.compare_func = operator.le if step > 0 else operator.ge
super().__init__()
def __iter__(self):
start = self.start
while self.compare_func(start, self.end):
yield start
start += self.step
for i in UnderneathAllRange(10, 5, -3):
print(i)
Output
10
7
Compare¶
Mapping¶
__getitem__
, __setitem__
, and __delitem__
are the three basic methods for a mapping to manage its items.
Access Items Through Attributes
If we have a dict, and we want to access the items directly through accessing its attributes, like below:
d = {'a': 1}
d.a
class UnderneathAllAttrDict(dict):
d = 0
def __getattribute__(self, attr):
return self.get(attr) if attr in self else super().__getattribute__(attr)
def __setattr__(self, attr, value):
try:
super().__setattr__(attr, value)
except:
print('no attr')
self[attr] = value