You need to understand the flow of __init__, __new__ and __call__

class Singleton(type): def __init__(self, *args, **kwargs): print 'calling __init__ of Singleton class', self print 'args: ', args print 'kwargs: ', kwargs super(Singleton, self).__init__(*args, **kwargs) self.__instance = None def __call__(self, *args, **kwargs): print 'running __call__ of Singleton', self print 'args: ', args print 'kwargs: ', kwargs, '\n\n' if self.__instance is None: self.__instance = super(Singleton, self).__call__(*args, **kwargs) return self.__instance class A(object): __metaclass__ = Singleton def __init__(self,a): print 'in __init__ of A: ', self self.a = a print 'self.a: ', self.a a=A(10) b=A(20) 

I copied this code from Ben's answer to the question of using Python __new__ and __init__? and changed it a bit. But I do not know the flow. Although I understand from a higher level what this code is intended to do. But, internally, how it works, I'm not quite sure.

When I run this code, I get the following output: -

 calling __init__ of Singleton class <class '__main__.A'> args: ('A', (<type 'object'>,), {'__module__': '__main__', '__metaclass__': <class '__main__.Singleton'>, '__init__': <function __init__ at 0x01F9F7B0>}) kwargs: {} running __call__ of Singleton <class '__main__.A'> args: (10,) kwargs: {} in __init__ of A: <__main__.A object at 0x01FA7A10> self.a: 10 running __call__ of Singleton <class '__main__.A'> args: (20,) kwargs: {} 

I cannot understand how args and kwargs have changed for __init__ and __call__ . When using metaclasses, this link ( What is a metaclass in Python? ) Explained how to use __new__ and a function as a metaclass. But I do not understand how __call__ used.

Can someone explain the flow? By this, I mean that the priority in which __new__ , __call__ , __init__ is called, and who calls them?

+6
source share
1 answer

Your code does not contain __new__ , so little can be said about this.

But you are creating a metaclass created when creating the time class A In other words, class A is the object itself and, as such, an instance of its metaclass Singleton .

So, let's see what happens:

After the completion of environment A (there are its methods, there is also its dict, ...), the class is created as an instance of a metaclass. Essentially a challenge

 A = Singleton('A', (object,), <the dict>) 

where <the dict> is the dict containing the class namespace (here: __module__ , __metaclass__ and __init__ ).

In this Singleton call, calling super(Singleton, self).__call__(*args, **kwargs) __new__ method, which returns a new instance, after which .__init__ .

This is why this happens:

 calling __init__ of Singleton class <class '__main__.A'> args: ('A', (<type 'object'>,), {'__module__': '__main__', '__metaclass__': <class '__main__.Singleton'>, '__init__': <function __init__ at 0x01F9F7B0>}) kwargs: {} 

After creating A you use it by creating it:

 a = A(10) 

It causes A A is an instance of Singleton , so Singleton.__call__ is called - with the effect you see:

 running __call__ of Singleton <class '__main__.A'> args: (10,) kwargs: {} 

Singleton.__call__ calls type.__call__ , this calls A.__new__ and A.__init__ :

 in __init__ of A: <__main__.A object at 0x01FA7A10> self.a: 10 

Then you do

 b = A(20) 

which calls Singleton.__call__ :

 running __call__ of Singleton <class '__main__.A'> args: (20,) kwargs: {} 

Here, the super call is suppressed and the old object is returned.

+7
source

Source: https://habr.com/ru/post/928101/


All Articles