五分钟理解元类(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 ORM(Object 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]五分钟理解元类(Metaclasses)相关推荐

  1. Python进阶:理解元类创建类ABCMeta

    Python进阶:Python进阶:理解元类创建类ABCMeta 一.理解元类(Meta class) 1.1 元类直观理解 1.2 Python官方文档给出的元类描述 二.理解抽象基类(ABC, A ...

  2. Python——五分钟理解函数式编程与闭包

    函数式编程 函数式编程这个概念我们可能或多或少都听说过,刚听说的时候不明觉厉,觉得这是一个非常黑科技的概念.但是实际上它的含义很朴实,但是延伸出来许多丰富的用法. 在早期编程语言还不是很多的时候,我们 ...

  3. python 什么是原类_Python 什么是元类(metaclasses)?

    1.什么是类 在理解元类之前,我们必须先掌握Python中的类(class). 和大多数语言一样,Python中的类知识用来描述如何"生成一个对象": 但是,在Python中,类不 ...

  4. 两句话轻松掌握python最难知识点——元类

    两句话掌握python最难知识点--元类 千万不要被所谓"元类是99%的python程序员不会用到的特性"这类的说辞吓住.因为每个中国人,都是天生的元类使用者 学懂元类,你只需要知 ...

  5. 五分钟理解什么是面向对象

    昨天讲了MVC,有同学表示还想了解一些软件开发架构方面的姿势.我琢磨了半天,列了不少技术名词,本来想挑一个出来讲一讲,写了一半发现有很多前置知识之前没涉及,于是决定把坑填一填,先从基础的「面向对象」讲 ...

  6. 【Python面试题】-元类

    [Python面试题]-元类 1.Python 中类方法.类实例方法.静态方法有何区别? 类方法:是类对象的方法,在定义时需要在上方使用"@classmethod"进行装饰,形参为 ...

  7. 五分钟理解什么是接口

    五分钟理解什么是接口   在IT和互联网领域里面,这个词在不同场景下都会出现,比如"USB接口","让后台给我提供一个接口,我直接调用这个接口","这 ...

  8. Python面向对象魔法、元类简介及使用

    文章目录 一.反射实战案例 二.面向对象魔法方法 三.魔法方法笔试题 四.元类简介 五.产生类的两种方式 六.元类基本使用 七.元类进阶 一.反射实战案例 1.获取配置文件中所有大写的配置 小写的直接 ...

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

    1.type()函数 #type()函数既可以返回一个对象的类型,又可以创建出新的类型, # 比如,我们可以通过type()函数创建出Hello类,而无需通过class Hello(object).. ...

最新文章

  1. graphs菜单_图形用户界面菜单全面解析
  2. php实现微信企业向用户付款
  3. MySQL · 源码分析 · 一条insert语句的执行过程
  4. 生成0到1之间随机数的C代码
  5. 计算机学院迎新活动总结,大学迎新活动总结
  6. [高级光照]球谐光照
  7. RandomAccessFile读写txt文件中文乱码
  8. 第1章——操作系统概论
  9. 第二届上汽零束SOA平台开发者大会揭幕,智能汽车生态加速落地
  10. Python实现简单自动升级exe程序版本并自动运行
  11. android支持wifi11ad,不得不知道的WIFI标准:802.11ad、ah、af
  12. Qt5 QFileDialog中文英文交界处乱码问题
  13. 使用golang链接达梦数据库
  14. Vision Transformer(VIT)代码分析——保姆级教程
  15. 刀马旦计算机音乐,刀马旦 MIDI File Download :: MidiShow
  16. 如何检测本计算机耗电量,如何查看我的电脑到底费不费电?
  17. 记一次作业:完成企业网络安全运营建设方案
  18. 2_31_HTML的标签及列表_190910
  19. 盘点:35 个 Java 代码优化魔鬼细节
  20. Java实现斗地主升级版

热门文章

  1. MySQL-MHA数据库高可用
  2. GUET七星瓢虫2022年考核题目c语言部分复现
  3. win7 php oracle数据库,Win764位系统下PHP连接Oracle数据库,win7oracle_PHP教程
  4. bootstrap 英文日历_时间日期日历控件(bootstrap-datetimepicker)
  5. iSpring Suite教程:iSpring Suite 9系统要求(下)
  6. 从无到有的基于QT软件的DIY桌面番茄钟(上)
  7. WebRTC笔记之十六:腾讯云CentOS 7.6搭建Janus之编译安装
  8. 最好玩的计算机游戏排行,电脑十大耐玩单机游戏-pc上最好玩的单机游戏-pc好玩的单机游戏排行_侠游戏网...
  9. 自定义比例的GS噪声和椒盐噪声的加入和阿尔法修正的均值滤波的实现
  10. Loading动画的最佳实现方式