This article example describes the principle and usage of metaclass in python. Shared for your reference, as follows:
What is metaclass.
A metaclass (metaclass) is the class used to create the class. In the previous article,python dynamic class creationAs we mentioned in the "Metaclass" section, one way to understand what a metaclass is is to think of it as follows.
MyClass = MetaClass() MyObject = MyClass()
Metaclass is programming magic inside python.
Also in a previous post, thepython dynamic class creationThe article "Dynamic Class Creation" describes type, which allows you to create a class in the following way.
MyClass = type('MyClass', (), {})
The fundamental reason for this is that type is a metaclass, and python uses type to create all sorts of classes behind it. What I don't understand is why it's "type" instead of "type", probably because str is used to create strings, int is used to create shaped objects, and type is used to create class objects, so it's better to use lowercase.
Anything in python is an object. This includes int,str,function,class and so on. They are all created from a class, which we can check by looking at the __class__ attribute.
>>> age = 35 >>> age.__class__ <type 'int'> >>> name = 'bob' >>> name.__class__ <type 'str'> >>> def foo(): pass >>> foo.__class__ <type 'function'> >>> class Bar(object): pass >>> b = Bar() >>> b.__class__ <class '__main__.Bar'>
Checking the __class__ attribute
>>> a.__class__.__class__ <type 'type'> >>> age.__class__.__class__ <type 'type'> >>> foo.__class__.__class__ <type 'type'> >>> b.__class__.__class__ <type 'type'>
What do you see? The results are all "type", which is actually a metaclass built into python. Of course, you can create your own metaclass. Here's an important attribute.
__metaclass__ attribute
When you are writing a class, you can add the __metaclass__ attribute.
class Foo(object): __metaclass__ = something... [...]
If you do, then python will call metaclass to create the Foo class, which is a bit confusing, don't you think?
python will look for __metaclass__ in your class definition, and if it finds it, it will use that metaclass to create the Foo class, and if it doesn't find it, it will use type to create the class... as mentioned in the previous post. So, when you
class Foo(Bar): pass
pyton will parse it as follows: if there is a __metaclass__ in Foo, if so, use metaclass to create a class object with the name "Foo". If it is not found, look at the base class Bar to see if there is a __metaclass__ in it, and if there is not, look at the module level to see if there is a __metaclass__, and if there is not, call type to create the class. If not, see if the base class Bar has __metaclass__, and if the base class does not, see if the module level has __metaclass__, and if it does not, call type to create the class.
Now the question is, what exactly can be done inside a __metaclass__? The conclusion is: something that creates a class. What creates a class is actually the type, or a subclass of the type.
Customizing metaclass
The main purpose of metaclass is to make some automatic changes when creating classes. For example, to use an inappropriate analogy, we intend to make all class attributes in a module uppercase. One way to handle this is to use __metaclass__ (declared on the module).
We're going to use metaclass to make all properties uppercase. A __metaclass__ doesn't have to be a class, it can be a method that can be called. Let's start with a simple example
def upper_attr(future_class_name, future_class_parents, future_class_attr): """ Return a class object, with the list of its attribute turned into uppercase. """ # pick up any attribute that doesn't start with '__' attrs = ((name, value) for name, value in future_class_attr.items() if not ('__')) # turn them into uppercase uppercase_attr = dict(((), value) for name, value in attrs) # let `type` do the class creation return type(future_class_name, future_class_parents, uppercase_attr) __metaclass__ = upper_attr # this will affect all classes in the module class Foo(): # global __metaclass__ won't work with "object" though # but we can define __metaclass__ here instead to affect only this class # and this will work with "object" childrend bar = 'bip' print hasattr(Foo, 'bar') # Out: False print hasattr(Foo, 'BAR') # Out: True f = Foo() print # Out: 'bip'
Now use a class for
# remember that `type` is actually a class like `str` and `int` # so you can inherit from it class UpperAttrMetaclass(type): # __new__ is the method called before __init__ # it's the method that creates the object and returns it # while __init__ just initializes the object passed as parameter # you rarely use __new__, except when you want to control how the object # is created. # here the created object is the class, and we want to customize it # so we override __new__ # you can do some stuff in __init__ too if you wish # some advanced use involves overriding __call__ as well, but we won't # see this def __new__(upperattr_metaclass, future_class_name, future_class_parents, future_class_attr): attrs = ((name, value) for name, value in future_class_attr.items() if not ('__')) uppercase_attr = dict(((), value) for name, value in attrs) return type(future_class_name, future_class_parents, uppercase_attr)
Obviously this isn't very oop, calling directly on thetype
method, instead of calling the parent class's__new__
method, do so below:
class UpperAttrMetaclass(type): def __new__(upperattr_metaclass, future_class_name, future_class_parents, future_class_attr): attrs = ((name, value) for name, value in future_class_attr.items() if not ('__')) uppercase_attr = dict(((), value) for name, value in attrs) # reuse the type.__new__ method # this is basic OOP, nothing magic in there return type.__new__(upperattr_metaclass, future_class_name, future_class_parents, uppercase_attr)
You may have noticed that upperattr_metaclass , which is actually equivalent to theself
, self in a common class method. a more general method is as follows:
class UpperAttrMetaclass(type): def __new__(cls, name, bases, dct): attrs = ((name, value) for name, value in () if not ('__')) uppercase_attr = dict(((), value) for name, value in attrs) return super(UpperAttrMetaclass, cls).__new__(cls, name, bases, uppercase_attr)
The above example allows you to understand the metaclass, and also to understand the__init__
Methods.__new__
method to make a hook.Of course it is also possible to make a hook in the__call__
Inside of that do the job, but more people like to do it in the__init__
Modify it inside.
Readers interested in more Python related content can check out this site's topic: thePython Object-Oriented Programming Introductory and Advanced Tutorials》、《Python Data Structures and Algorithms Tutorial》、《Summary of Python function usage tips》、《Summary of Python string manipulation techniques》、《Summary of Python coding manipulation techniquesand thePython introductory and advanced classic tutorials》
I hope that the description of this article will be helpful for you Python Programming.