Strange Metaclass.

Source: Internet
Author: User

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)

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.