SoFunction
Updated on 2024-12-19

The principle and usage of metaclass in python.

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 thetypemethod, 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.