Python中的元类是什么?


Answers

类作为对象

在理解元类之前,您需要掌握Python中的类。 Python从Smalltalk语言中借用了一个非常奇怪的概念,即类是什么类。

在大多数语言中,类只是描述如何生成对象的代码段。 这在Python中也是如此:

>>> class ObjectCreator(object):
...       pass
...

>>> my_object = ObjectCreator()
>>> print(my_object)
<__main__.ObjectCreator object at 0x8974f2c>

但是类不仅仅是Python。 类也是对象。

是的,对象。

只要您使用关键字class ,Python就会执行它并创建一个OBJECT。 指令

>>> class ObjectCreator(object):
...       pass
...

在内存中创建一个名为“ObjectCreator”的对象。

这个对象(类)本身能够创建对象(实例),这就是为什么它是一个类

但是,它仍然是一个客体,因此:

  • 你可以将它分配给一个变量
  • 你可以复制它
  • 你可以给它添加属性
  • 你可以将它作为函数参数传递

例如:

>>> print(ObjectCreator) # you can print a class because it's an object
<class '__main__.ObjectCreator'>
>>> def echo(o):
...       print(o)
...
>>> echo(ObjectCreator) # you can pass a class as a parameter
<class '__main__.ObjectCreator'>
>>> print(hasattr(ObjectCreator, 'new_attribute'))
False
>>> ObjectCreator.new_attribute = 'foo' # you can add attributes to a class
>>> print(hasattr(ObjectCreator, 'new_attribute'))
True
>>> print(ObjectCreator.new_attribute)
foo
>>> ObjectCreatorMirror = ObjectCreator # you can assign a class to a variable
>>> print(ObjectCreatorMirror.new_attribute)
foo
>>> print(ObjectCreatorMirror())
<__main__.ObjectCreator object at 0x8997b4c>

动态创建类

由于类是对象,因此可以像任何对象一样快速创建它们。

首先,您可以使用class在函数中创建一个class

>>> def choose_class(name):
...     if name == 'foo':
...         class Foo(object):
...             pass
...         return Foo # return the class, not an instance
...     else:
...         class Bar(object):
...             pass
...         return Bar
...
>>> MyClass = choose_class('foo')
>>> print(MyClass) # the function returns a class, not an instance
<class '__main__.Foo'>
>>> print(MyClass()) # you can create an object from this class
<__main__.Foo object at 0x89c6d4c>

但它并不那么活跃,因为你还得自己写全班。

由于类是对象,它们必须由某些东西生成。

当你使用class关键字时,Python会自动创建这个对象。 但是与Python中的大多数事情一样,它为您提供了一种手动执行的方法。

记住功能type ? 良好的旧功能,让你知道什么类型的对象是:

>>> print(type(1))
<type 'int'>
>>> print(type("1"))
<type 'str'>
>>> print(type(ObjectCreator))
<type 'type'>
>>> print(type(ObjectCreator()))
<class '__main__.ObjectCreator'>

那么, type具有完全不同的能力,它也可以即时创建类。 type可以将类的描述作为参数,并返回一个类。

(我知道,根据传递给它的参数,相同的函数可能有两种完全不同的用法,这很愚蠢,由于Python的向后兼容性,这是一个问题)

type工作方式如下:

type(name of the class,
     tuple of the parent class (for inheritance, can be empty),
     dictionary containing attributes names and values)

例如:

>>> class MyShinyClass(object):
...       pass

可以通过以下方式手动创建:

>>> MyShinyClass = type('MyShinyClass', (), {}) # returns a class object
>>> print(MyShinyClass)
<class '__main__.MyShinyClass'>
>>> print(MyShinyClass()) # create an instance with the class
<__main__.MyShinyClass object at 0x8997cec>

您会注意到我们使用“MyShinyClass”作为类的名称,并将其用作保存类引用的变量。 它们可以不同,但​​没有理由使事情复杂化。

type接受一个字典来定义类的属性。 所以:

>>> class Foo(object):
...       bar = True

可以翻译成:

>>> Foo = type('Foo', (), {'bar':True})

并用作普通班级:

>>> print(Foo)
<class '__main__.Foo'>
>>> print(Foo.bar)
True
>>> f = Foo()
>>> print(f)
<__main__.Foo object at 0x8a9b84c>
>>> print(f.bar)
True

当然,你可以继承它,所以:

>>>   class FooChild(Foo):
...         pass

将会:

>>> FooChild = type('FooChild', (Foo,), {})
>>> print(FooChild)
<class '__main__.FooChild'>
>>> print(FooChild.bar) # bar is inherited from Foo
True

最终你会想要添加方法到你的班级。 只需使用正确的签名定义一个函数,并将其作为属性进行分配。

>>> def echo_bar(self):
...       print(self.bar)
...
>>> FooChild = type('FooChild', (Foo,), {'echo_bar': echo_bar})
>>> hasattr(Foo, 'echo_bar')
False
>>> hasattr(FooChild, 'echo_bar')
True
>>> my_foo = FooChild()
>>> my_foo.echo_bar()
True

在动态创建类后,您可以添加更多方法,就像向通常创建的类对象中添加方法一样。

>>> def echo_bar_more(self):
...       print('yet another method')
...
>>> FooChild.echo_bar_more = echo_bar_more
>>> hasattr(FooChild, 'echo_bar_more')
True

你可以看到我们要去的地方:在Python中,类是对象,并且可以动态地动态创建类。

这就是Python在使用关键字class时所做的事情,它通过使用元类来实现。

什么是元类(最后)

元类是创建类的'东西'。

你可以定义类来创建对象,对吗?

但是我们了解到Python类是对象。

好吧,元类是创建这些对象的东西。 他们是班级的班级,你可以这样描绘他们:

MyClass = MetaClass()
my_object = MyClass()

你已经看到这种type可以让你做这样的事情:

MyClass = type('MyClass', (), {})

这是因为函数type实际上是一个元类。 type是Python用于在幕后创建所有类的元类。

现在你想知道为什么它是用小写写的,而不是Type

那么,我想这是一个与str一致的问题,创建字符串对象的类以及创建整数对象的类。 type只是创建类对象的类。

你可以通过检查__class__属性来看到。

一切,我的意思是一切,都是Python中的一个对象。 包括整数,字符串,函数和类。 所有这些都是对象。 所有这些都是从一个班级创建的:

>>> 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'>

现在,什么是__class____class__

>>> age.__class__.__class__
<type 'type'>
>>> name.__class__.__class__
<type 'type'>
>>> foo.__class__.__class__
<type 'type'>
>>> b.__class__.__class__
<type 'type'>

所以,元类就是创建类对象的东西。

如果你愿意,你可以称它为“班级工厂”。

type是Python使用的内置元类,但是当然,您可以创建自己的元类。

__metaclass__属性

编写一个类时,您可以添加__metaclass__属性:

class Foo(object):
    __metaclass__ = something...
    [...]

如果你这样做,Python将使用元类创建类Foo

小心,这很棘手。

您先写class Foo(object) ,但类对象Foo不会在内存中创建。

Python会在类定义中寻找__metaclass__ 。 如果发现它,它将使用它来创建对象类Foo 。 如果没有,它将使用type来创建类。

多读几次。

当你这样做时:

class Foo(Bar):
    pass

Python执行以下操作:

Foo是否有__metaclass__属性?

如果是,则在内存中创建一个类对象(我说的是一个类对象,留在这里),名称为Foo通过使用__metaclass__

如果Python找不到__metaclass__ ,它将在MODULE级别寻找__metaclass__ ,并尝试做同样的事情(但只适用于不继承任何东西的类,基本上是旧式类)。

然后,如果它根本找不到任何__metaclass__ ,它将使用Bar的(第一个父)自己的元类(可能是默认type )来创建类对象。

请注意, __metaclass__属性不会被继承,父类( Bar.__class__ )的元类将会被继承。 如果Bar使用了一个__metaclass__属性,该属性使用type() (而不是type.__new__() )创建Bar ,则该子类不会继承该行为。

现在最大的问题是,你可以在__metaclass____metaclass__什么?

答案是:可以创建一个类的东西。

什么可以创建一个班级? type或任何子类或使用它的东西。

自定义元类

元类的主要目的是在创建时自动更改类。

您通常对API进行此操作,您希望创建与当前上下文匹配的类。

想象一个愚蠢的例子,你决定你模块中的所有类都应该用大写字母来写属性。 有几种方法可以做到这一点,但一种方法是在模块级设置__metaclass__

这样,这个模块的所有类都将使用这个元类创建,并且我们只需要告诉元类将所有属性都转换为大写。

幸运的是, __metaclass__实际上可以是任何可调用的,它不需要是一个正式的类(我知道,名称中有'class'的东西不需要成为类,但是这很有帮助)。

所以我们将从一个简单的例子开始,通过使用一个函数。

# the metaclass will automatically get passed the same argument
# that you usually pass to `type`
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 '__' and uppercase it
    uppercase_attr = {}
    for name, val in future_class_attr.items():
        if not name.startswith('__'):
            uppercase_attr[name.upper()] = val
        else:
            uppercase_attr[name] = val

    # 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" children
    bar = 'bip'

print(hasattr(Foo, 'bar'))
# Out: False
print(hasattr(Foo, 'BAR'))
# Out: True

f = Foo()
print(f.BAR)
# Out: 'bip'

现在,让我们做同样的事情,但使用一个真正的类作为元类:

# 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):

        uppercase_attr = {}
        for name, val in future_class_attr.items():
            if not name.startswith('__'):
                uppercase_attr[name.upper()] = val
            else:
                uppercase_attr[name] = val

        return type(future_class_name, future_class_parents, uppercase_attr)

但这不是真正的OOP。 我们直接调用type ,并且不会覆盖或调用父类__new__ 。 我们开始做吧:

class UpperAttrMetaclass(type):

    def __new__(upperattr_metaclass, future_class_name,
                future_class_parents, future_class_attr):

        uppercase_attr = {}
        for name, val in future_class_attr.items():
            if not name.startswith('__'):
                uppercase_attr[name.upper()] = val
            else:
                uppercase_attr[name] = val

        # 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)

你可能已经注意到了额外的参数upperattr_metaclass 。 没有什么特别的: __new__总是接收它定义的类,作为第一个参数。 就像你有接受实例作为第一个参数的普通方法或类方法的定义类一样。

当然,为了清楚起见,我在这里使用的名字很长,但是对于self ,所有的参数都有常规名称。 所以一个真正的生产元类将如下所示:

class UpperAttrMetaclass(type):

    def __new__(cls, clsname, bases, dct):

        uppercase_attr = {}
        for name, val in dct.items():
            if not name.startswith('__'):
                uppercase_attr[name.upper()] = val
            else:
                uppercase_attr[name] = val

        return type.__new__(cls, clsname, bases, uppercase_attr)

我们可以通过使用super来使它更加清洁,这将减轻继承(因为是的,你可以有元类,继承自类继承的元类):

class UpperAttrMetaclass(type):

    def __new__(cls, clsname, bases, dct):

        uppercase_attr = {}
        for name, val in dct.items():
            if not name.startswith('__'):
                uppercase_attr[name.upper()] = val
            else:
                uppercase_attr[name] = val

        return super(UpperAttrMetaclass, cls).__new__(cls, clsname, bases, uppercase_attr)

而已。 关于元类没有什么更多。

使用元类代码的复杂性背后的原因不是因为元类,这是因为你通常使用元类来进行扭曲的东西,依赖于内省,操纵继承,__ __dict__等变量。

事实上,元类对于做黑魔法特别有用,因此也是复杂的东西。 但是它们本身很简单:

  • 拦截一个类的创建
  • 修改班级
  • 返回修改的类

为什么你会使用元类而不是函数?

由于__metaclass__可以接受任何可调用,为什么要使用一个类,因为它显然更复杂?

这样做有几个原因:

  • 意图很清楚。 当你阅读UpperAttrMetaclass(type) ,你知道会发生什么
  • 你可以使用OOP。 元类可以从元类继承,覆盖父类方法。 元类甚至可以使用元类。
  • 如果您指定了元类别类,但不具有元类函数,则类的子类将是其元类的实例。
  • 你可以更好地构建你的代码。 你从来没有像上面的例子那样使用元类作为微不足道的东西。 这通常是复杂的。 有能力制作多种方法并将它们分组到一个类中,这对于使代码更易于阅读非常有用。
  • 你可以挂钩__new__ __init____init____call__ 。 这将允许你做不同的事情。 即使通常您可以在__new__完成所有__new__ ,但有些人使用__init__更加舒适。
  • 这些被称为元类,该死的! 它一定意味着什么!

为什么你会使用元类?

现在是个大问题。 为什么你会使用一些不太容易出错的错误特征?

那么,通常你不会:

元类是更深的魔法,99%的用户不应该担心。 如果你想知道你是否需要他们,你就不会(实际需要他们的人确切地知道他们需要他们,并且不需要为什么解释)。

Python大师蒂姆彼得斯

元类的主要用例是创建一个API。 一个典型的例子是Django ORM。

它允许你定义这样的东西:

class Person(models.Model):
    name = models.CharField(max_length=30)
    age = models.IntegerField()

但是,如果你这样做:

guy = Person(name='bob', age='35')
print(guy.age)

它不会返回一个IntegerField对象。 它将返回一个int ,甚至可以直接从数据库中获取它。

这是可能的,因为models.Model定义了__metaclass__ ,它使用了一些魔法,将您刚刚用简单语句定义的Person变成复杂的数据库字段钩子。

Django通过暴露一个简单的API并使用元类来创建一些复杂的外观,从这个API重新创建代码来完成幕后的真实工作。

最后一个字

首先,你知道类是可以创建实例的对象。

事实上,类本身就是实例。 元类。

>>> class Foo(object): pass
>>> id(Foo)
142630324

一切都是Python中的一个对象,它们都是类的实例或元类的实例。

除了type

type实际上是它自己的元类。 这不是您可以在纯Python中重现的东西,而是通过在实现级别上作弊而完成的。

其次,元类很复杂。 你可能不希望将它们用于非常简单的课程改动。 您可以通过使用两种不同的技术来改变课程:

99%的时间你需要改变班级,你最好使用这些。

但98%的时间,你根本不需要改变班级。

Question

什么是元类,我们用它们做什么?




The type() function can return the type of an object or create a new type,

for example, we can create a Hi class with the type() function and do not need to use this way with class Hi(object):

def func(self, name='mike'):
    print('Hi, %s.' % name)

Hi = type('Hi', (object,), dict(hi=func))
h = Hi()
h.hi()
Hi, mike.

type(Hi)
type

type(h)
__main__.Hi

In addition to using type() to create classes dynamically, you can control creation behavior of class and use metaclass.

According to the Python object model, the class is the object, so the class must be an instance of another certain class. By default, a Python class is instance of the type class. That is, type is metaclass of most of the built-in classes and metaclass of user-defined classes.

class ListMetaclass(type):
    def __new__(cls, name, bases, attrs):
        attrs['add'] = lambda self, value: self.append(value)
        return type.__new__(cls, name, bases, attrs)

class CustomList(list, metaclass=ListMetaclass):
    pass

lst = CustomList()
lst.add('custom_list_1')
lst.add('custom_list_2')

lst
['custom_list_1', 'custom_list_2']

Magic will take effect when we passed keyword arguments in metaclass, it indicates the Python interpreter to create the CustomList through ListMetaclass. new (), at this point, we can modify the class definition, for example, and add a new method and then return the revised definition.




元类的一个用途是自动向实例添加新的属性和方法。

例如,如果你看看Django模型 ,他们的定义看起来有点混乱。 它看起来好像只是定义类属性:

class Person(models.Model):
    first_name = models.CharField(max_length=30)
    last_name = models.CharField(max_length=30)

但是,在运行时,Person对象会充满各种有用的方法。 看到一些惊人的metaclassery source




The tl;dr version

The type(obj) function gets you the type of an object.

The type() of a class is its metaclass .

To use a metaclass:

class Foo(object):
    __metaclass__ = MyMetaClass



Role of a metaclass's __call__() method when creating a class instance

If you've done Python programming for more than a few months you'll eventually stumble upon code that looks like this:

# define a class
class SomeClass(object):
    # ...
    # some definition here ...
    # ...

# create an instance of it
instance = SomeClass()

# then call the object as if it's a function
result = instance('foo', 'bar')

The latter is possible when you implement the __call__() magic method on the class.

class SomeClass(object):
    # ...
    # some definition here ...
    # ...

    def __call__(self, foo, bar):
        return bar + foo

The __call__() method is invoked when an instance of a class is used as a callable. But as we've seen from previous answers a class itself is an instance of a metaclass, so when we use the class as a callable (ie when we create an instance of it) we're actually calling its metaclass's __call__() method. At this point most Python programmers are a bit confused because they've been told that when creating an instance like this instance = SomeClass() you're calling it's __init__() method. Some who've dug a bit deeper know that before __init__() there's __new__() . Well, today another layer of truth is being revealed, before __new__() there's the metaclass's __call__() .

Let's study the method call chain from specifically the perspective of creating an instance of a class.

This is a metaclass that logs exactly the moment before an instance is created and the moment it's about to return it.

class Meta_1(type):
    def __call__(cls):
        print "Meta_1.__call__() before creating an instance of ", cls
        instance = super(Meta_1, cls).__call__()
        print "Meta_1.__call__() about to return instance."
        return instance

This is a class that uses that metaclass

class Class_1(object):

    __metaclass__ = Meta_1

    def __new__(cls):
        print "Class_1.__new__() before creating an instance."
        instance = super(Class_1, cls).__new__(cls)
        print "Class_1.__new__() about to return instance."
        return instance

    def __init__(self):
        print "entering Class_1.__init__() for instance initialization."
        super(Class_1,self).__init__()
        print "exiting Class_1.__init__()."

And now let's create an instance of Class_1

instance = Class_1()
# Meta_1.__call__() before creating an instance of <class '__main__.Class_1'>.
# Class_1.__new__() before creating an instance.
# Class_1.__new__() about to return instance.
# entering Class_1.__init__() for instance initialization.
# exiting Class_1.__init__().
# Meta_1.__call__() about to return instance.

The code above doesn't actually do anything other than logging the task and then delegating the actual work to the parent (ie keeping the default behavior). So with type being Meta_1 's parent class, we can imagine that this would be the pseudo implementation of type.__call__() :

class type:
    def __call__(cls, *args, **kwarg):

        # ... maybe a few things done to cls here

        # then we call __new__() on the class to create an instance
        instance = cls.__new__(cls, *args, **kwargs)

        # ... maybe a few things done to the instance here

        # then we initialize the instance with its __init__() method
        instance.__init__(*args, **kwargs)

        # ... maybe a few more things done to instance here

        # then we return it
        return instance

We can see that the metaclass's __call__() method is the one that's called first. It then delegates creation of the instance to the class's __new__() method and initialization to the instance's __init__() . It's also the one that ultimately returns the instance.

From the above it stems that the metaclass's __call__() is also given the opportunity to decide whether or not a call to Class_1.__new__() or Class_1.__init__() will eventually be made. Over the course of its execution it could actually return an object that hasn't been touched by either of these methods. Take for example this approach to the singleton pattern:

class Meta_2(type):
    singletons = {}

    def __call__(cls, *args, **kwargs):
        if cls in Meta_2.singletons:
            # we return the only instance and skip a call to __new__() 
            # and __init__()
            print ("{} singleton returning from Meta_2.__call__(), "
                   "skipping creation of new instance.".format(cls))
            return Meta_2.singletons[cls]

        # else if the singleton isn't present we proceed as usual
        print "Meta_2.__call__() before creating an instance."
        instance = super(Meta_2, cls).__call__(*args, **kwargs)
        Meta_2.singletons[cls] = instance
        print "Meta_2.__call__() returning new instance."
        return instance

class Class_2(object):

    __metaclass__ = Meta_2

    def __new__(cls, *args, **kwargs):
        print "Class_2.__new__() before creating instance."
        instance = super(Class_2, cls).__new__(cls)
        print "Class_2.__new__() returning instance."
        return instance

    def __init__(self, *args, **kwargs):
        print "entering Class_2.__init__() for initialization."
        super(Class_2, self).__init__()
        print "exiting Class_2.__init__()."

Let's observe what happens when repeatedly trying to create an object of type Class_2

a = Class_2()
# Meta_2.__call__() before creating an instance.
# Class_2.__new__() before creating instance.
# Class_2.__new__() returning instance.
# entering Class_2.__init__() for initialization.
# exiting Class_2.__init__().
# Meta_2.__call__() returning new instance.

b = Class_2()
# <class '__main__.Class_2'> singleton returning from Meta_2.__call__(), skipping creation of new instance.

c = Class_2()
# <class '__main__.Class_2'> singleton returning from Meta_2.__call__(), skipping creation of new instance.

a is b is c # True



Python 3 update

There are (at this point) two key methods in a metaclass:

  • __prepare__ , and
  • __new__

__prepare__ lets you supply a custom mapping (such as an OrderedDict ) to be used as the namespace while the class is being created. You must return an instance of whatever namespace you choose. If you don't implement __prepare__ a normal dict is used.

__new__ is responsible for the actual creation/modification of the final class.

A bare-bones, do-nothing-extra metaclass would like:

class Meta(type):

    def __prepare__(metaclass, cls, bases):
        return dict()

    def __new__(metacls, cls, bases, clsdict):
        return super().__new__(metacls, cls, bases, clsdict)

一个简单的例子:

Say you want some simple validation code to run on your attributes -- like it must always be an int or a str . Without a metaclass, your class would look something like:

class Person:
    weight = ValidateType('weight', int)
    age = ValidateType('age', int)
    name = ValidateType('name', str)

As you can see, you have to repeat the name of the attribute twice. This makes typos possible along with irritating bugs.

A simple metaclass can address that problem:

class Person(metaclass=Validator):
    weight = ValidateType(int)
    age = ValidateType(int)
    name = ValidateType(str)

This is what the metaclass would look like (not using __prepare__ since it is not needed):

class Validator(type):
    def __new__(metacls, cls, bases, clsdict):
        # search clsdict looking for ValidateType descriptors
        for name, attr in clsdict.items():
            if isinstance(attr, ValidateType):
                attr.name = name
                attr.attr = '_' + name
        # create final class and return it
        return super().__new__(metacls, cls, bases, clsdict)

A sample run of:

p = Person()
p.weight = 9
print(p.weight)
p.weight = '9'

生产:

9
Traceback (most recent call last):
  File "simple_meta.py", line 36, in <module>
    p.weight = '9'
  File "simple_meta.py", line 24, in __set__
    (self.name, self.type, value))
TypeError: weight must be of type(s) <class 'int'> (got '9')

Note : This example is simple enough it could have also been accomplished with a class decorator, but presumably an actual metaclass would be doing much more.

The 'ValidateType' class for reference:

class ValidateType:
    def __init__(self, type):
        self.name = None  # will be set by metaclass
        self.attr = None  # will be set by metaclass
        self.type = type
    def __get__(self, inst, cls):
        if inst is None:
            return self
        else:
            return inst.__dict__[self.attr]
    def __set__(self, inst, value):
        if not isinstance(value, self.type):
            raise TypeError('%s must be of type(s) %s (got %r)' %
                    (self.name, self.type, value))
        else:
            inst.__dict__[self.attr] = value



我认为ONLamp对元类编程的介绍写得很好,并且尽管已经有几年的历史,但对这个主题有很好的介绍。

http://www.onlamp.com/pub/a/python/2003/04/17/metaclasses.html

简而言之:类是创建实例的蓝图,元类是创建类的蓝图。 可以很容易地看出,在Python类中也需要成为第一类对象才能实现这种行为。

我从来没有自己写过,但我认为在Django框架中可以看到元类的最好用法之一。 模型类使用元类方法来实现编写新模型或表单类的声明式风格。 当元类创建类时,所有成员都可以自定义类。

剩下要说的是:如果你不知道什么是元类,那么你不需要它们的概率是99%。






Links