Skip to content

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
How should we implement it?

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

https://docs.python.org/3/reference/datamodel.html