Add by Zhj: This is the most clear explanation I have seen for Metaclass, the example is very good, is a case of victory thousand words
Original: http://wiki.jikexueyuan.com/project/explore-python/Class/metaclass.html
The meta-Class (Metaclass) in Python is a depth of magic, and we may be less exposed to meta-classes, and this article will use some simple examples to understand this magic.
Class is also an object
In Python, everything is the object. A string, a list, a dictionary, a function is an object, and a class is an object, so you can:
- Assigning a class to a variable
- To pass a class as a function parameter
- To use a class as the return value of a function
- To create a class dynamically at run time
See a simple example:
class Foo(object): foo = Trueclass Bar(object): bar = Truedef echo(cls): print clsdef select(name): if name == ‘foo‘: return Foo # 返回值是一个类 if name == ‘bar‘: return Bar>>> echo(Foo) # 把类作为参数传递给函数 echo<class ‘__main__.Foo‘>>>> cls = select(‘foo‘) # 函数 select 的返回值是一个类,把它赋给变量 cls>>> cls__main__.Foo
A familiar and unfamiliar type
In daily use, we often use it object
to derive a class, in fact, in this case, the Python interpreter calls type
to create the class.
Here, there type
it is, yes, you know type
, we often use it to determine the type of an object, such as:
class Foo(object): Foo = True>>> type(10)<type ‘int‘>>>> type(‘hello‘)<type ‘str‘>>>> type(Foo())<class ‘__main__.Foo‘>>>> type(Foo)<type ‘type‘>
In fact, in type
addition to the type of object that can be returned, it can also be used to dynamically create classes (objects). Let's take a look at a few examples to digest this sentence.
Use type
to create a class (object) in the following way:
Type (the class name, the tuple of the parent class (which can be empty for inheritance), contains the dictionary of properties and methods (name and value))
The simplest case
Suppose you have the following class:
class Foo(object): pass
Now, we don't use class
keywords to define, and use type
, as follows:
Foo = type(‘Foo‘, (object, ), {}) # 使用 type 创建了一个类对象
The above two methods are equivalent. We see that we type
receive three parameters:
- The 1th parameter is the string ' Foo ', which indicates the class name
- The 2nd parameter is a tuple (object,) that represents all the parent classes
- The 3rd argument is a dictionary, here is an empty dictionary, indicating that no properties and methods are defined
On top of that, we used to type()
create a class named Foo, and then assign it to the variable foo, and we can certainly assign it to other variables, but there's no need to get yourself into trouble at the moment.
Next, let's look at using:
>>> print Foo<class ‘__main__.Foo‘>>>> print Foo()<__main__.Foo object at 0x10c34f250>
Where there are properties and methods
Suppose you have the following class:
class Foo(object): foo = True def greet(self): print ‘hello world‘ print self.foo
Use type
to create this class, as follows:
def greet(self): print ‘hello world‘ print self.fooFoo = type(‘Foo‘, (object, ), {‘foo‘: True, ‘greet‘: greet})
The effect of the above two methods is the same, look under use:
>>> f = Foo()>>> f.fooTrue>>> f.greet<bound method Foo.greet of <__main__.Foo object at 0x10c34f890>>>>> f.greet()hello worldTrue
The case of inheritance
Take a look at the inheritance, assuming the following parent class:
class Base(object): pass
We derive a Foo class from Base, as follows:
class Foo(Base): foo = True
Use type
to create, as follows:
Foo = type(‘Foo‘, (Base, ), {‘foo‘: True})
What is a meta-class (Metaclass)
A meta-class (Metaclass) is a callable object used to create a class (object). The callable object here can be a function or class, and so on. But in general, we use classes as meta-classes. For instance objects, classes, and meta classes, we can use the following diagram to describe:
类是实例对象的模板,元类是类的模板+----------+ +----------+ +----------+| | | | | || | instance of | | instance of | || instance +------------>+ class +------------>+ metaclass|| | | | | || | | | | |+----------+ +----------+ +----------+
We used type
to create the Class (object) in front of it, in fact, it type
is a meta class.
So what is the use of the meta-class? What do you want to use ...?
The primary purpose of the meta-class is to control the creation behavior of the class. Let's just take a look at some examples to digest this sentence.
Use of meta-classes
Let's start with a simple example, assuming the following class:
class Foo(object): name = ‘foo‘ def bar(self): print ‘bar‘
Now we want to prefix this class with the method and property name my_
, that is, name becomes my_name,bar to My_bar, and we want to add an echo method. Of course, there are many ways to demonstrate the use of the meta-class approach.
1. First, define a meta-class, according to the default habit, the class name end with Metaclass, the code is as follows:
class PrefixMetaclass(type): def __new__(cls, name, bases, attrs): # 给所有属性和方法前面加上前缀 my_ _attrs = ((‘my_‘ + name, value) for name, value in attrs.items()) _attrs = dict((name, value) for name, value in _attrs) # 转化为字典 _attrs[‘echo‘] = lambda self, phrase: phrase # 增加了一个 echo 方法 return type.__new__(cls, name, bases, _attrs) # 返回创建后的类
The above code has several points to note:
- Prefixmetaclass
type
inherit from, this is because Prefixmetaclass is used to create the class
__new__
is a __init__
special method that was previously called to create an object and return the created object, explaining its parameters as follows:
- CLS: Class currently ready to be created
- Name: Names of classes
- Bases: Collection of classes ' parent classes
- Attrs: The properties and methods of a class, is a dictionary
2. Next, we need to instruct Foo to use Prefixmetaclass to customize the class.
In Python2, we only need to add a __metaclass__
property to Foo, as follows:
class Foo(object): __metaclass__ = PrefixMetaclass name = ‘foo‘ def bar(self): print ‘bar‘
In Python3, do this:
class Foo(metaclass=PrefixMetaclass): name = ‘foo‘ def bar(self): print ‘bar‘
Now, let's take a look at using:
>>> f = Foo()>>> f.name # name 属性已经被改变---------------------------------------------------------------------------AttributeError Traceback (most recent call last)<ipython-input-774-4511c8475833> in <module>()----> 1 f.nameAttributeError: ‘Foo‘ object has no attribute ‘name‘>>>>>> f.my_name‘foo‘>>> f.my_bar()bar>>> f.echo(‘hello‘)‘hello‘
As you can see, Foo's original attribute name has become my_name, and the method bar has become My_bar, which is the magic of the Meta class.
Take a look at an example of inheritance, here's the complete code:
class PrefixMetaclass(type): def __new__(cls, name, bases, attrs): # 给所有属性和方法前面加上前缀 my_ _attrs = ((‘my_‘ + name, value) for name, value in attrs.items()) _attrs = dict((name, value) for name, value in _attrs) # 转化为字典 _attrs[‘echo‘] = lambda self, phrase: phrase # 增加了一个 echo 方法 return type.__new__(cls, name, bases, _attrs)class Foo(object): __metaclass__ = PrefixMetaclass # 注意跟 Python3 的写法有所区别 name = ‘foo‘ def bar(self): print ‘bar‘class Bar(Foo): prop = ‘bar‘
Among them, Prefixmetaclass and Foo are the same as the previous definition, except for the addition of Bar, which inherits from Foo. First let's take a look at using:
>>> b = Bar()>>> b.prop # 发现没这个属性---------------------------------------------------------------------------AttributeError Traceback (most recent call last)<ipython-input-778-825e0b6563ea> in <module>()----> 1 b.propAttributeError: ‘Bar‘ object has no attribute ‘prop‘>>> b.my_prop‘bar‘>>> b.my_name‘foo‘>>> b.my_bar()bar>>> b.echo(‘hello‘)‘hello‘
We found that Bar has no prop this property, but there is my_prop this property, which is why?
Originally, when we define class Bar(Foo)
, Python will first look in the current class, Bar, __metaclass__
if not found, will be in the parent class Foo, if not find, continue to find __metaclass__
in the parent of Foo, so continue, if not found in any parent class __metaclass__
, it is will be found in the module hierarchy, and if not found, the class will be created with type.
Here, we found in Foo __metaclass__
, Python uses Prefixmetaclass to create bar, that is, the meta-class implicitly inherits the subclass, although not shown in the subclass, __metaclass__
which explains why the bar's Prop property is dynamically modified to My_prop.
Write here, do not know you understand the meta-class? Hope to understand, if you do not understand, see a few times it ~
Summary
- In Python, a class is also an object.
- Class to create the instance, and the Meta class to create the class.
- The meta-class has done three things:
- Block creation of classes
- Modifying the definition of a class
- Returns the Modified class
- When you create a class, the interpreter calls the meta-class to generate it, and defining a normal class that inherits from object means calling the type to create it.
Resources
- Oop-what is a metaclass in Python? -Stack Overflow
- Deep understanding of the meta-class in Python (metaclass)-Bole Online
- Using Meta class-Liaoche's official website
- Python Basics: meta-class
- Using class decorator and Metaclass in Python
Strange Metaclass (Turn)