[Python]五分钟理解元类(Metaclasses)

翻译 2008年10月10日 11:34:00

五分钟理解元类(Metaclasses

真的,它并非巫术。


原文地址:http://www.voidspace.org.uk/python/articles/five-minutes.shtml

日期:16 September, 2008.

译者:赖勇浩(http://blog.csdn.net/lanphaday

 “元类的魔幻变化比 99% 的用户所担心的更多,当你搞不懂是否真的需要用它的时候,就是不需要。”

—Tim Peters

本文源于在 PyCon UK 2008 上的一个快速演讲。

元类被称为 Python 中的“深奥的巫术”。尽管你需要用到它的地方极少(除非你基于 zope 编程),可事实上它的基础理论其实令人惊讶地易懂。

一切皆对象

  • 一切皆对象
  • 一切都有类型
  •  class”和“type”之间本质上并无不同
  • 类也是对象
  • 它们的类型是 type

以前,术语 type 用于内置类型,而术语 class 用于用户定义的类,但自 Pythoon 2.2 以来“class”和“type”本质上并无不同。

对于旧风格(old-style)类的类型是 types.ClassType

真的,这是真的

Python 2.5.1 (r251:54869, Apr 18 2007, 22:08:04)
>>> class Something(object):
...     pass
...
>>> Something
<class '__main__.Something'>
>>> type(Something)
<type 'type'>

从这里可以看出在交互式解释器中创建的类是一个 first class 的对象。

类的类是……

它的元类……

就像对象是类的实例一样,类是它的元类的实例。

调用元类可以创建类。

确切来说,Python 中的其它对象也是如此。

因此当你创建一个类时……

解释器会调用元类来生成它……

定义一个继承自 object 的普通类意味着调用 type 来创建它:

>>> help(type)

Help on class type in module __builtin__:

 

class type(object)

 |  type(object) -> the object's type

 |  type(name, bases, dict) -> a new type

type 的第二种用法尤为重要。当 Python 解释器在执行一条类定义语句时(如例子中最初的两行代码之后),它会用下面的参数调用 type

  • 字符串形式的类名
  • 元组形式的基类序列——在我们的例子中是只有一个元素的元组(’one-pl’[1],如(object,)
  • 包括由名字影射的类成员(类属性、方法等)的字典

简单模拟

>>> def __init__(self):
...     self.message = 'Hello World'
...
>>> def say_hello(self):
...     print self.message
...
>>> attrs = {'__init__': __init__, 'say_hello': say_hello}
>>> bases = (object,)
>>> Hello = type('Hello', bases, attrs)
>>> Hello
<class '__main__.Hello'>
>>> h = Hello()
>>> h.say_hello()
Hello World

以上代码创建了类属性的字典,然后调用 type 来创建了名为 Hello 的类。

__metaclass__ 的魔法

只要在类定义中把 __metaclass__ 设置为任意有着与 type 相同参数的可调用对象,就能够提供自定义的元类。

通常使用从 type 继承的方法:

class PointlessMetaclass(type):
    
def __new__(meta, name, bases, attrs):
        
# do stuff...
        return type.__new__(meta, name, bases, attrs)

重要的是在 __new__ 方法中我们能够读取或改变传入的用以创建新类的参数。从而能够内省属性字典和改动、增加或者删除成员。

尽管当实例化一个类时这两个函数都会被调用,但覆盖 __new__ __init__ 更为重要。__init__ 初始化一个实例,而 __new__ 的职责是创建它。因此如果元类用以自定义类的创建,就需要覆盖 type __new__

使用新类而非仅仅提供工厂函数的原因在于如果使用工厂函数(那样只是调用 type)的话元类不会被继承。

In Action...

>>> class WhizzBang(object):
...     __metaclass__ = PointlessMetaclass
...
>>> WhizzBang
<class '__main__.WhizzBang'>
>>> type(WhizzBang)
<class '__main__.PointlessMetaClass'>

WhizzBang 是一个类,但它现在已经不是 type 的实例,而是我们自定义的元类的实例了……

这有什么用?

很好的问题,元类将用在创建使用了它的新类时调用,这里是一些关于这样做的好处的观点:

  • 装饰(Decorate)类的所有方法,用以日志记录或者性能剖分。
  • 自动 Mix-in 新方法
  • 在创建时注册类。(例如自动注册插件或从类成员创建数据库模式。)
  • 提供接口注册,功能自动发现和接口适配。
  • 类校验:防止子类化,校验所有的方法是否都有 docstrings

最重要之处在于元类中是在最后对 type 的调用时才真正创建类,所以可以自由地随你喜欢地改变属性字典(以及名称和元组形式的基类序列)。

一些流行的 Python ORMObject Relational Mappers(对象关系影射),用以和数据库协同工作)也如此使用元类。

哦,还有因为元类是继承的,所以你能够提供一个使用了你的元类的基类,而继承自它的子类就无需显式声明它了。

但是……

我曾未需要使用它来编写代码……(我们用它来剖分,也在 Ironclad 项目广泛应用它,但我不编写这些)。

还有,这一切只适用于 Python 2.x,其中的机制在 Python 3 中已经改变了。

type(type) is type

Python 2.6 中现在也可用使用  class decorators 来实现许多以前可能需要用元类来实现的东西。

最后,还有一个极尽奇技淫巧的例子(稍为深入,但仍然不难消化),可以去看看 The Selfless Metaclass。它通过字节码和方法签名重写来避免显式地声明 self

[1]

 'one-pl'是指只有一个元素的元组。

 

深入理解python元类

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

metaclass--Python元类终极解密(五分钟理解)

看了好多关于Python元类的解释,一直不明白到底为什么会有这个东西,这个东东到底是什么,啥时候会用到呢?~~~或许这个问题让很多人都迷惑过,当然也包括我这个Python菜鸟。下面就让我们一起来学习这...
  • z_lstone
  • z_lstone
  • 2013年11月10日 21:29
  • 1065

Django模型类Meta元数据详解

来源:https://my.oschina.net/liuyuantao/blog/751337 简介 使用内部的class Meta 定义模型的元数据...
  • gavinking0110
  • gavinking0110
  • 2016年11月11日 10:09
  • 1159

【Python]五分钟理解元类(Metaclasses)【转载】

原文链接为:http://blog.csdn.net/gzlaiyonghao/article/details/3048947 五分钟理解元类(Metaclasses) 真的,它并非巫...
  • mathsYouth
  • mathsYouth
  • 2015年06月29日 12:15
  • 156

<转>五分钟真的能理解python元类(Metaclasses)

[Python]五分钟理解元类(Metaclasses)[Python]五分钟理解元类(Metaclasses)             五分钟理解元类(Metaclasses) 真的,它并非巫术...
  • heiyeah09
  • heiyeah09
  • 2013年06月20日 19:38
  • 365

五分钟理解元类(Metaclasses)

原文地址:http://blog.csdn.net/lanphaday/article/details/3048947 五分钟理解元类(Metaclasses) 真的,它并...
  • kuyucman
  • kuyucman
  • 2013年06月06日 01:11
  • 646

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

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

python类:描述器Descriptors和元类MetaClasses

描述器(Descriptors) 描述器决定了对象属性是如何被访问的。描述器的作用是定制当你想引用一个属性时所发生的操作。 构建描述器的方法是至少定义以下三个方法中的一个。需要注意,下文中的in...
  • pipisorry
  • pipisorry
  • 2016年01月01日 12:52
  • 1541

五分钟战胜Python字符编码

本文不谈复杂的理论,就经验教你字符处理八字真言:确定编码,同类交互。了解完本文,你可以轻松解决文字处理,特殊平台(Windows?)下的编码,爬虫编码等问题。...
  • jfmz6oFQMALUmv6f
  • jfmz6oFQMALUmv6f
  • 2016年07月29日 14:43
  • 417

五分钟战胜 Python 字符编码

转自:http://python.jobbole.com/85482/对于很多接触Python的人而言,字符的处理和语言整体的温顺可靠相比显得格外桀骜不驯难以驾驭。本文不谈复杂的理论,就经验教你字符处...
  • luckytanggu
  • luckytanggu
  • 2016年07月02日 17:05
  • 576
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:[Python]五分钟理解元类(Metaclasses)
举报原因:
原因补充:

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