Metaclass
Everything in python is an object, so the class you define must also be an object, which is instantiated by a class. This tired class is called metaclass. How to find metaclass
class People: def __init__(self,name,age): self.name=name self.age=age print(type(People)) # The result is < class' type '>, which proves that People are generated by calling the metaclass type, that is, the default metaclass is type)
When the class keyword helps us create a class, it must help us call the metaclass People=type(...). What are the parameters passed in when People calls type? It must be the key component of a class. A class has three components, namely
1. Class name_ name='StanfordTeacher'
2. Base class_bases=(object,)
3. Class namespace_ DIC, the class namespace is obtained by executing the class body code
When calling type, the above three parameters will be passed in sequence
To sum up, the class keyword helps us create a class, which should be subdivided into the following four processes:
- Get the class name class_name='People'
- Get the base class of the class_bases=(object,)
- Execute the class body code to get the class namespace class_dict={...}
- Class People=type(class_name='People',class_bases=(object,),class_dict = {...}) is obtained by metaclass instantiation
Custom metaclasses control the creation of classes
A class does not declare its own metaclass. The default is type. In addition to using the built-in metaclass type, we can also define the metaclass by inheriting type, and then specify the metaclass for a class using the metaclass keyword parameter
class Mymeta(type): # Only by inheriting the type class can it be called a metaclass, otherwise it is an ordinary user-defined class pass class Teacher(object,metaclass=Mymeta): school='Qinghua' def __init__(self,name,age): self.name=name self.age=age def say(self): print('%s says welcome to Qinghua' %self.name)
Custom meta classes can control the generation of classes. The generation of classes is actually the call process of meta classes, that is, Teacher=Mymeta('Teacher',(object,) {}). Calling Mymeta first produces an empty object Teacher, and then passes simultaneous interpreting the parameters in Mymeta parenthesis to Mymeta under Mymeta. init__ Method, complete initialization,
class Mymeta(type): def __init__(self,class_name,class_bases,class_dic): # print(self) # <class '__main__.StanfordTeacher'> # print(class_bases) # (<class 'object'>,) # print(class_dic) # {'__module__': '__main__', '__qualname__': 'Teacher', 'school': 'Qinghua', '__init__': <function Teacher.__init__ at 0x102b95ae8>, 'say': <function Teacher.say at 0x10621c6a8>} super(Mymeta, self).__init__(class_name, class_bases, class_dic) # Reuse the function of the parent class if class_name.islower(): raise TypeError('Class name%s Please change to hump body' %class_name) if '__doc__' not in class_dic or len(class_dic['__doc__'].strip(' \n')) == 0: raise TypeError('Class must have a document comment, and the document comment cannot be empty') # Teacher=Mymeta('Teacher',(object),{...}) class Teacher(object,metaclass=Mymeta): """ class Teacher Document comments for """ school='Qinghua' def __init__(self,name,age): self.name=name self.age=age def say(self): print('%s says welcome to Qinghua' %self.name)
Call of user-defined metaclass control class Teacher
__ call__ Method is automatically triggered when calling the object, and the return value of the calling object is__ call__ Method
class Mymeta(type): def __call__(self, *args, **kwargs): print(self) # <class '__main__.Teacher'> print(args) # ('lili', 18) print(kwargs) # {} return 123 class Teacher(object,metaclass=Mymeta): school='Qinghua' def __init__(self,name,age): self.name=name self.age=age def say(self): print('%s says welcome to Qinghua' %self.name) # Calling Teacher is in the calling Teacher class__ call__ method # Then pass the Teacher to self, the overflow location parameter to *, and the overflow keyword parameter to** t1=Teacher('lili',18) print(t1) # 123
Three things happen when calling t1=Teacher('lili',18):
- Generate an empty object obj
- Call__ init__ Method initializes object obj
- Returns the initialized obj
In the Teacher class__ call__ Methods should also do these three things
class Mymeta(type): def __call__(self, *args, **kwargs): # 1. Call__ new__ Generate an empty object obj obj=self.__new__(self) # self here is a Teacher class and must pass parameters, representing the object obj that creates a Teacher # 2. Call__ init__ Initialize empty object obj self.__init__(obj,*args,**kwargs) # 3. Returns the initialized object obj return obj class Teacher(object,metaclass=Mymeta): school='Qinghua' def __init__(self,name,age): self.name=name self.age=age def say(self): print('%s says welcome to the Stanford to learn Python' %self.name) t1=Teacher('lili',18) print(t1.__dict__) # {'name': 'lili', 'age': 18}
Example above__ call__ Equivalent to a template, we can rewrite it on this basis__ call__ To control the process of calling Teacher, such as making all properties of Teacher objects private
class Mymeta(type): def __call__(self, *args, **kwargs): # The Teacher class is passed in obj=self.__new__(self) # The new method of the parent class of the Teacher class creates the Teacher class self.__init__(obj,*args,**kwargs) # Initialize the Teacher class obj.__dict__={'_%s__%s' %(self.__name__,k):v for k,v in obj.__dict__.items()} # Privatize the properties of the Teacher class return obj class Teacher(object,metaclass=Mymeta): school='Qinghua' def __init__(self,name,age): self.name=name self.age=age def say(self): print('%s says welcome to Qinghua' %self.name) t1=Teacher('lili',18) print(t1.__dict__) # {'_Teacher__name': 'lili', '_Teacher__age': 18}
Inheritance + metaclass -- attribute lookup
Suppose the following inheritance relationships exist: object Teacher inherits object Foo, object Foo inherits object Bar, and object Bar inherits object object
It can be seen from the above that classes can also be viewed as objects, so the attribute search should also follow the principle of inheritance: Teacher - > foo - > bar - > Object - > mymeta - > type
Therefore, attribute search should be divided into two layers. One layer is the search of object layer (MRO based on c3 algorithm), and the other layer is the search of class layer (i.e. metaclass layer)
Search order:
1. First object layer: Teacher - > foo - > bar - > object
2. Then metaclass layer: mymeta - > type
Singleton mode
Single instance: that is, a single instance. It means that the result of multiple instantiations of the same class points to the same object, which is used to save memory space
Singleton pattern is a common software design pattern. Its core structure contains only a special class called singleton class. The single instance mode can ensure that there is only one instance of a class in the system, and the instance is easy to be accessed by the outside world, so as to facilitate the control of the number of instances and save system resources. If you want only one object of a class to exist in the system, singleton mode is the best solution.
There are three key points of singleton mode:
- First, a class can only have one instance
- Second, it must create this instance itself
- Third, it must provide this example to the whole system by itself
Method 1: with the help of new method
This way is not unique, but the essence is to help_ instance marks the status and judges according to the status
class Singleton(object): def __new__(cls, *args, **kwargs): if not hasattr(cls,'_instance'): orig=super(Singleton,cls) cls._instance=orig.__new__(cls,*args,**kwargs) return cls._instance class MyClass(Singleton): a=1 one=MyClass() two=MyClass() # one and two are identical. You can use id(), = =, is to check print(one.a) # 1 print(id(one)) # 2565285375728 print(id(two)) # 2565285375728 print(one == two) # True print(one is two) # True
Method 2: customize the metaclass to implement the singleton mode
""" class Singleton Medium__init__stay Myclass The declaration is executed Myclass=Singleton() Myclass()When executing, the parent class is executed first__call__Method( object,Singleton All as Myclass Parent class of, According to the depth first algorithm, the Singleton Medium__call__(),Singleton Medium__call__()Singleton mode is written) """ class Singleton(type): def __init__(self, name, bases, dict): super(Singleton,self).__init__(name,bases, dict) self._instance = None def __call__(self, *args, **kwargs): if self._instance is None: self._instance = super(Singleton,self).__call__(*args, **kwargs) return self._instance class MyClass(object,metaclass=Singleton): a = 1 one=MyClass() two=MyClass() print(id(one)) # 1553247294800 print(id(two)) # 1553247294800 print(one == two) # True print(one is two) # True
Method 3: define a decorator to implement the singleton mode
def singleton(cls, *args, **kwargs): instances = {} def _singleton(): if cls not in instances: instances[cls] = cls(*args, **kwargs) return instances[cls] return _singleton @singleton class MyClass3(object): a = 1 one = MyClass3() two = MyClass3() print(id(one)) # 2880466769232 print(id(two)) # 2880466769232 print(one == two) # True print(one is two) # True class Singleton(object): __instance=None def __init__(self): pass def __new__(cls, *args, **kwargs): if Singleton.__instance is None: Singleton.__instance=object.__new__(cls,*args, **kwargs) return Singleton.__instance one=Singleton() two=Singleton() print(id(one)) # 2488569943376 print(id(two)) # 2488569943376 print(one == two) # True print(one is two) # True
There is another way. We all know that the module is imported only once, that is, put the content you want in a py file and import it directly when you need it. It is also an implementation of singleton mode