理解python中的元类(metaclass)

翻译 2018年04月15日 11:16:00
本文是根据stackoverflow上关于“What are metaclasses in Python?”的回答翻译总结而成的。原数据连接:
https://stackoverflow.com/questions/100003/what-are-metaclasses-in-python

1. 类对象(class as object)

在了解元类(metaclass)之前, 首先得熟悉一下python中的类(class)。python对于什么是类有一个很独特的定义,借鉴与Smalltalk编程语言。

在很多编程语言中,类仅仅是一段用来描述如何产生对象的代码。python中的类也有这种功能。
>>> class ObjectCreator(object):
    ... pass...
>>> my_object = ObjectCreator()
>>> print(my_object)
<__main__.ObjectCreator object at 0x8974f2c>

但是,在python中,类的作用远不止这个。
类本身也是对象。
因为类是对象,所以我们可以对其进行很多操作:
  • 赋值给一个变量
  • 复制类
  • 添加属性
  • 作为参数传递给函数
>>> class ObjectCreator(object):
...     pass
...
>>> 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>

2. 动态创建类(Creating classes dynamically)

由于类是对象,所以你可以在任何地方创建它们,就像其他类型对象一样。
例如,在一个函数内通过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>

但是这并不是动态地创建类,因为你还是需要把类的整体写出来。
既然类是对象,那么它肯定是由什么东西生成的。这就引出了元类——用来创建类的‘东西’


3.  元类是一个类(class)对象

普通的类定义了该类的实例对象所具有的属性和方法,元类就定义了普通类所具有的属性和方法。即实例对象是普通类的实例化,普通类是元类的实例化。如下图所示:


Python中一切皆对象(object)。对象包括了数字(int), 字符串(string), 函数(functions)和类(class)。这些对象都需要通过调用元类来构建,所以元类通常被用作类工厂(class-factory)。 例如,我们通过调用类来创建类的实例,python中通过调用元类来创建一个新的类。结合__init__和__new__方法,元类就允许你在创建新类是添加一些额外的内容,甚至是完全重载该类。

除了类工厂外,元类还定义了类的类型(type),所以你可以用它来做更多的事情。例如,给元类定义一些常规的方法。元类中的方法(metaclass-method)就像是类方法(classmethod),所以你可以直接通过类名来调用这些方法,而不需要通过实例来调用。事实上,通过实例是无法调用元类中的方法的。这也是元类中方法与类方法的区别。


4.  __metaclass__属性

当我们创建类时,可以在类的定义中添加__metaclass__属性。属性值是一些创建类的操作。
class Foo(object):
__metaclass__ = something...
[...]
添加完后,python就会用元类来创建类Foo。
注意,整个过程其实是这样的:
  • 首先当你输入 class Foo(object)后,类Foo并没有在内存中被创建。python会在类Foo的定义中寻找__metaclass__。
  • 如果找到了,则就会使用__metaclass__来创建类。
  • 如果没有找到,就会调用type来创建类。

4. type

type是Python中常见的一个元类。你没有听错,type是一个类(以前我一直以为type是一个内置函数呢!),用来构建类对象。所以type(type)返回的是class type。类似的元类还有str和int, 分别用来构建字符串对象和整数对象。他们都有__class__属性,值为class ‘type’

>>> type(type)
<class 'type'>
>>> str.__class__
<class 'type'>
>>> int.__class__
<class 'type'>

除了返回对象的类型外,type还有一个截然不同的功能——动态创建类。type接受对类的描述作为参数,然后返回一个类。
例如:
>>> 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>
type可以通过传入字典参数来定义类的属性。
>>> Foo = type('Foo', (), {'bar':True})
上述代码等同于:
>>> class Foo(object):
...     bar = True
type产生的类支持一切类的操作,包括继承。
>>> print(Foo)
<class '__main__.Foo'
>>>> print(Foo.bar)
True
>>> f = Foo()
>>> print(f)
<__main__.Foo object at 0x8a9b84c
>>>> print(f.bar)True

>>> FooChild = type('FooChild', (Foo,), {})
等价于
>>> class FooChild(Foo):
...     pass

5. 结语

类是对象,可以用来创建实例。而类本身又是元类的实例。
python中一切皆为对象,所有的对象都是类的实例或者元类的实例。
type是一个例外。type是其自身的元类。它是定义在解析器层面上的,不是你通过纯python代码可以复制的。

python中的元类Metaclass

python中的元类Metaclass理解元类之前需要学习的知识如果说让我们创建一个类,最先想到的肯定是用class创建,当我们使用class创建类的时候,python解释器自动创建这个对象,但是py...
  • weixin_35955795
  • weixin_35955795
  • 2016-10-31 19:17:33
  • 3277

python——type()、metaclass元类和精简ORM框架

1、type()函数 #type()函数既可以返回一个对象的类型,又可以创建出新的类型, # 比如,我们可以通过type()函数创建出Hello类,而无需通过class Hello(object)....
  • jaccty
  • jaccty
  • 2017-08-18 12:28:48
  • 380

深入学习Django源码基础1 - 深刻理解Python中的元类(metaclass)

http://blog.jobbole.com/21351/
  • watsy
  • watsy
  • 2013-08-26 00:18:31
  • 2696

python3学习笔记:元类metaclass

转载过来格式很丑,不能看,所以作罢。详见这篇博客http://blog.jobbole.com/21351/...
  • xionghuixionghui
  • xionghuixionghui
  • 2017-03-26 17:56:40
  • 405

元类metaclass -- python

在看元类之前,先看看python中对象与类之间的关系。对象与对象在python中,类的定义常见有两种方式: 1, python内置的类,例如:str, int 等 2, 自定类:常见的是使用cla...
  • a1368783069
  • a1368783069
  • 2016-08-11 02:03:06
  • 327

Python技巧:元类(Metaclasses)和利用Type构建的动态类(Dynamic Classes)

原文链接:Improve Your Python: Metaclasses and Dynamic Classes With Type `metaclass`和`type`关键字在Python代码...
  • dysj4099
  • dysj4099
  • 2014-01-29 13:18:11
  • 8236

深入理解python元类

类和对象在理解什么是元类之前,有必要先理解下,什么是类。 什么是类?通俗的讲,类就是用来创建对象的代码片。在python中,类还有一个奇特的特性,就是类,本身也是一个对象。怎么理解?——在你定义一个类...
  • Allenalex
  • Allenalex
  • 2017-01-09 20:57:18
  • 2370

Python之类的继承和多态

派生类可以继承父类的公有成员,但是不能继承其私有成员。如果需要在派生类中调用基类的方法,可以使用内置函数super()或者通过‘’基类名.方法名()'的方式来说实现。 Python支持多继承,若父类中...
  • lgqiii
  • lgqiii
  • 2017-08-02 22:04:19
  • 124

Python元类编程——with_metaclass

最近刚接触python的元类,网络上有比较详细的介绍,这里是在看Django时候发现一点关于元类的应用,做个笔记。from django.utils import sixclass A(type): ...
  • liuyuan_jq
  • liuyuan_jq
  • 2017-04-07 18:52:09
  • 1416

Python Metaclass(元类)

python中元类是创建类对象的对象,这句话说着有点拗口。想了解元类首先我们要了解一下类,类是用来创建对象的一种规则。在Python中类也是一种对象。每种对象都是有类型的,那么类是属于哪种类型? 我...
  • a540366413
  • a540366413
  • 2017-07-17 14:57:59
  • 129
收藏助手
不良信息举报
您举报文章:理解python中的元类(metaclass)
举报原因:
原因补充:

(最多只允许输入30个字)