Python基础:元类

1、概述

Python虽然是多范式的编程语言,但它的数据模型倒是 纯面向对象 的。与那些仅在语法层面声称纯OO的编程语言(如Java)相比,Python的这种纯粹性更加深刻骨髓。html

在Python的世界里,一切皆为对象:数值序列字典函数模块文件类实例 等等,无一例外(参考 Data model)。其中,“类也是对象” 的概念最让人匪夷所思,这彻底超越了传统的OO思想。python

元类(metaclass)是Python 2.2中引入的概念,利用元类能够 定制类的建立行为Customizing class creation)。“元类” 的概念一样让人难以理解,然而理解 “元类” 是理解 “类也是对象” 的关键。编程

2、经典阐述

对于元类的理解,目前为止,最经典的阐述莫过于Stack Overflow上面的这篇帖子 What is a metaclass in Python?,e-satis 神通常的回复让人醍醐灌顶,看完后基本就了然于胸了。markdown

若是以为看英文比较吃力,这里有一篇中文译版 深入理解Python中的元类(metaclass)(注:英文原版最近有更新,但核心内容不变)。编程语言

3、核心总结

一、类的建立过程

对于类定义:函数

class Foo(Base):
    def say(self):
        print 'hello'

Python解释器 执行class语句 时,处理步骤以下:code

  1. 肯定元类mcls。元类的查找优先级为:htm

    • 首先查找 类Foo 是否拥有属性__metaclass__
    • 不然查找 类Foo的父类 是否具备属性__metaclass__
    • 不然查找 类Foo所在模块 是否具备全局变量__metaclass__
    • 不然使用默认元类(经典类:types.ClassType;新式类:type
  2. 使用元类mcls建立类Foo。建立语意等价于:对象

    def say(self):
        print 'hello'
    
    # 元类的参数:mcls(name, bases, dict)
    Foo = mcls('Foo', (Base,), {'say': say})
  3. 建立成功后,类Foo 是 元类mcls实例blog

综上:建立类 实际上是一种更高级别的 实例化过程,本质上与 建立类实例 类似。

实例化过程 实例 语意形式
建立类Foo 元类mcls 类Foo class Foo: pass <=> Foo = mcls('Foo', (), {})
建立类实例foo 类Foo 类实例foo foo = Foo()

二、元类的使用惯例

原则上,元类能够是:任何接受参数 name, bases, dict 并返回 可调用对象(参考 metaclass)。

例如元类能够是 函数

def metacls_func(name, bases, dict):
    # do customizing here
    return type(name, bases, dict)

根据最佳实践指导,更好的习惯是使用 做为元类,典型风格以下:

class MetaCls(type):
    def __new__(cls, name, bases, dict):
        # do customizing here
        return super(MetaCls, cls).__new__(cls, name, bases, dict)

注意:

  • 元类能够继承自另外一个元类,也能够使用其余元类
  • 除了经常使用的__new__,还能够借助__init____call__来定制被建立的类

4、简单案例

一、默认行为

1)经典类(Classic classes)

Old的三种等价定义:

class Old: pass

class Old:
    __metaclass__ = types.ClassType

Old = types.ClassType('Old', (), {})

Old是元类types.ClassType的实例:

>>> isinstance(Old, types.ClassType)
True

2)新式类(New-style classes)

New的三种等价定义:

class New(object): pass

class New:
    __metaclass__ = type

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

New是元类type的实例:

>>> isinstance(New, type)
True

二、使用元类

为全部类打上做者标签:

class AuthorTag(type):
    def __new__(cls, name, bases, dict):
        dict['__author__'] = 'RussellLuo'
        return super(AuthorTag, cls).__new__(cls, name, bases, dict)

class MyBlog:
    __metaclass__ = AuthorTag

class MyGitHub:
    __metaclass__ = AuthorTag

如今,类MyBlog和类MyGitHub都免费得到了做者签名:

>>> MyBlog.__author__
'RussellLuo'
>>> MyGitHub.__author__
'RussellLuo'

5、实践为王

请记住上面的简单案例,若是您想从本文中得到对Python元类仅有的一点印象。纸上得来终觉浅,绝知此事要躬行,开始吧。

相关文章
相关标签/搜索