A note on what Python beginners have learned about Python 3 metaclasses The comments in the code are intended for console output. We would appreciate it if you could point out any mistakes or improper expressions.
If you want to find out which class type an instance is, you can use type ().
class Hoge:
pass
h = Hoge()
print(type(h))
# <class '__main__.Hoge'>
Try applying type () to the Hoge class as well.
print(type(Hoge))
# <class 'type'>
This indicates that the Hoge class itself is an instance of type type. Just as h is an instance of the Hoge class, the Hoge class is also an instance of the type class. *** A class defined in Python3 becomes an instance of a special class (metaclass) called type. *** Normally, when a class is defined, type (classname, superclasses, attributes_dict) with three arguments is called, and an instance of the class is created. It is also possible to explicitly give three arguments to the type class and create a class instance instead of the "normal" definition method. The above Hoge class can be defined as ↓ using type. (Pass the class name in the first argument, the tuple of the parent class in the second argument, and the namespace dictionary in the third argument)
Hoge = type('Hoge', (), {})
h = Hoge()
print(type(h))
# <class '__main__.Hoge'>
The type class that creates a class instance is like a factory that creates (an instance of) a class and is called a *** metaclass ***. When the interpreter faces the declaration of the Hoge class, by default \ _ \ _ new \ _ \ _ of the type class is called and a class instance is created, but you can customize the metaclass by inheriting this type class. .. The following is an example of setting the MetaTest class that inherits type instead of the default type as the metaclass when declaring the class.
class MetaTest(type):
def __new__(cls, clsname, superclasses, attributedict):
print("Metaclass testing")
class HogeHoge(metaclass=MetaTest):
pass
#Metaclass testing
h = HogeHoge()
# TypeError: 'NoneType' object is not callable
MetaTest inherits from the default metaclass, the type class, and overrides the \ _ \ _ new \ _ \ _ method that creates a class instance. Here, the character string is just output without creating a class instance. Therefore, when declaring a HogeHoge class with MetaTest set as a metaclass, MetaTest. \ _ \ _ New \ _ \ _ that just returns a string instead of type. \ _ \ _ New \ _ \ _ that creates a class instance Called. The console also displayed "Test Metaclass". The next time I tried to instantiate the HogeHoge class, I got an error. The MetaTest class has not created an instance of the HogeHoge class (is a None object created?). If you override the parent class type \ _ \ _ new \ _ \ _, the class instance will not be created. Calling type. \ _ \ _ New \ _ \ _ in the return value of \ _ \ _ new \ _ \ _ to return a class instance or overriding \ _ \ _ init \ _ \ _ will work (\ _ \ _ new ) Class instance created when _ \ _ was called first?).
class MetaTestA(type):
def __new__(cls, clsname, superclasses, attributedict):
print("Metaclass A test")
return type.__new__(cls, clsname, superclasses, attributedict)
class MetaTestB(type):
def __init__(cls, clsname, superclasses, attributedict):
print("Metaclass B test")
class HogeHogeA(metaclass=MetaTestA):
pass
#Metaclass A test
class HogeHogeB(metaclass=MetaTestB):
pass
#Metaclass B test
a = HogeHogeA()
b = HogeHogeB()
print(type(a))
# <class '__main__.HogeHogeA'>
print(type(b))
# <class '__main__.HogeHogeB'>
You can control the behavior of class instances by customizing the metaclass. The here site that I referred to this time introduces a Singleton pattern like ↓ that utilizes metaclasses.
class Singleton(type):
_instances = {}
def __call__(cls, *args, **kwargs):
if cls not in cls._instances:
cls._instances[cls] = super(Singleton, cls).__call__(*args, **kwargs)
return cls._instances[cls]
class SingletonClass(metaclass=Singleton):
pass
class RegularClass():
pass
x = SingletonClass()
y = SingletonClass()
print(x == y)
# True
x = RegularClass()
y = RegularClass()
print(x == y)
# False
An instance with a \ _ \ _ call \ _ \ _ method (it seems to be called able) can call \ _ \ _ call \ _ \ _ like a function with the instance name (). Singleton, a metaclass that inherits type, overrides the type class \ _ \ _ call \ _ \ _. \ _ \ _ Call \ _ \ _ is called every time a SingletonClass class (a class that is an instance of Singleton) with Singleton set as a metaclass is described in the format of SingletonClass () (every time SingletonClass is instantiated). Will be done. Inside \ _ \ _ call \ _ \ _, it checks if the instance is stored in \ _instances, and if the instance does not exist, the \ _ \ _ call \ _ \ _ method of type, which is the parent class of Singleton, is called. , SingletonClass is instantiated (here \ _ \ _ call \ _ \ _ seems to instantiate SingletonClass, but I'm not sure about the details). If an instance already exists in \ _instances, no new instance will be created. On the other hand, RegularClass, whose metaclass is the default type class, is instantiated each time.
https://www.yunabe.jp/docs/python_metaclass.html https://www.python-course.eu/python3_metaclasses.php https://realpython.com/python-metaclasses/ https://teratail.com/questions/180387
Recommended Posts