creating-a-singleton-in-python和what-is-a-metaclass-in-python
下面这两段代码的执行结果反映了一个问题:很明显元类的存在会影响__call__和__new__的优先级,请问大神能否分析一下两者执行结果不同的原因?
class Singleton(object): def __new__(cls, *args, **kwargs): if not hasattr(cls, '_instance'): cls._instance = super(Singleton, cls).__new__(cls, *args, **kwargs) print('__new__') return cls._instance def __call__(cls, *args, **kwargs): if not hasattr(cls, '_instance'): cls._instance = super(Singleton, cls).__call__(*args, **kwargs) print('__call__') return cls._instance class Foo(Singleton): pass print('1') foo1 = Foo() print('2') foo2 = Foo() print(foo1 is foo2) # True
上面这段代码的执行结果
$ python non_metaclass.py 1 __new__ 2 __new__ True
class Singleton(type): def __new__(cls, *args, **kwargs): if not hasattr(cls, '_instance'): cls._instance = super(Singleton, cls).__new__(cls, *args, **kwargs) print('__new__') return cls._instance def __call__(cls, *args, **kwargs): if not hasattr(cls, '_instance'): cls._instance = super(Singleton, cls).__call__(*args, **kwargs) print('__call__') return cls._instance class Foo(metaclass=Singleton): # 不兼容Python2 pass print('1') foo1 = Foo() print('2') foo2 = Foo() print (foo1 is foo2) # True
上面这段代码的执行结果
$ python metaclass.py __new__ 1 __call__ 2 __call__ True
如果描述不够详细,请在评论区留一下言,我再改进。
I will modify it and explain it carefully here
The metaclass defines the class structure attributes, and the "__new__" and "__init__" methods in the class are used to process class instances
Every class we define can be understood as an instance of type
Okay, back to "__new__" and "__call__"
In the metaclass, "__new__" will be executed when you define the class. It will only be executed once. If two classes use this metaclass, OK, it will be executed twice
And __call__ will be called every time you instantiate it. In fact, it is the same as Foo.__new__, which means that if your Foo defines __new__, the __call__ in the metaclass will not be executed
The "__new__" of the metaclass can change the type you define. I defined Foo here as a list
It’s very hard to write so much. There are very few people who can correctly understand metaclass. I don’t know how to thank the author of the question
This is not a problem of metaclass affecting the priority of new and call, but that __new__ of metaclass will only be called once when creating a class. And this __new__ is used to create our class, as in your question. When was it created? When the interpreter interprets the Foo class, it will look for the __metaclass__ attribute in the class definition, and if it is found, use it to create the class. If not found, the built-in type will be used to create the class. Why not call it again? Because the metaclass has already created our class, we can't re-create the class every time Foo() is called. It can also be seen from your output that foo2 = Foo() does not output __new__. Because the class has been created by the metaclass at this time, you can just start using it directly. It is no different from the classes we usually use, so every time it is created, a new object is created. And why use __call__? Because Foo is a class created by the metaclass Singleton, you can think of Foo as an instance object of Singleton. So __call__ will be called every time Foo() is called. In __call__ we get the already created instance object. Isn't it just a singleton? .
Singleton
Let’s explain in detail through the code
After running, you will find that cls in the __call__ function is the class created by calling __new__ for the first and only time in the metaclass, which is Foo, and cls._instance is the instance object of our Foo. Every time Foo() is called, the same instance object is taken. Metaclasses are, after all, classes that create classes. Once created, the class is no different from the class you normally define.