一、概述

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

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

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

二、经典阐述

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

如果觉得看英文比较吃力,这里有一篇中文译版 深刻理解Python中的元类(metaclass)(注:英文原版最近有更新,但核心内容不变)。

三、核心总结

1、类的创建过程

对于类定义:

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

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

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

    • 首先查找 类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实例

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

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

2、元类的使用惯例

原则上,元类可以是:任何接受参数 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__来定制被创建的类

四、简单案例

1、默认行为

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

2、使用元类

为所有类打上作者标签:

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'

五、实践为王

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

Python基础:元类的更多相关文章

  1. python基础----元类metaclass

    1 引子 class Foo: pass f1=Foo() #f1是通过Foo类实例化的对象 python中一切皆是对象,类本身也是一个对象,当使用关键字class的时候,python解释器在加载cl ...

  2. 二十六. Python基础(26)--类的内置特殊属性和方法

    二十六. Python基础(26)--类的内置特殊属性和方法 ● 知识框架 ● 类的内置方法/魔法方法案例1: 单例设计模式 # 类的魔法方法 # 案例1: 单例设计模式 class Teacher: ...

  3. python基础——枚举类

    python基础——枚举类 当我们需要定义常量时,一个办法是用大写变量通过整数来定义,例如月份: JAN = 1 FEB = 2 MAR = 3 ... NOV = 11 DEC = 12 好处是简单 ...

  4. python基础——定制类

    python基础——定制类 看到类似__slots__这种形如__xxx__的变量或者函数名就要注意,这些在Python中是有特殊用途的. __slots__我们已经知道怎么用了,__len__()方 ...

  5. Python基础-类的探讨(class)

    Python基础-类的探讨(class) 我们下面的探讨基于Python3,我实际测试使用的是Python3.2,Python3与Python2在类函数的类型上做了改变 1,类定义语法  Python ...

  6. python 通过元类控制类的创建

    一.python中如何创建类? 1. 直接定义类 class A: a = 'a' 2. 通过type对象创建 在python中一切都是对象 在上面这张图中,A是我们平常在python中写的类,它可以 ...

  7. Python 的元类设计起源自哪里?

    一个元老级的 Python 核心开发者曾建议我们( 点击阅读),应该广泛学习其它编程语言的优秀特性,从而提升 Python 在相关领域的能力.在关于元编程方面,他的建议是学习 Hy 和 Ruby.但是 ...

  8. Python之元类详解

    一.引子 元类属于Python面向对象编程的深层魔法,99%的人都不得要领,一些自以为搞明白元类的人其实也是自圆其说,点到为止,从队元类的控制上来看就破绽百出,逻辑混乱: 二.什么是元类 一切源自于一 ...

  9. 谈谈Python中元类Metaclass(二):ORM实践

    什么是ORM? ORM的英文全称是“Object Relational Mapping”,即对象-关系映射,从字面上直接理解,就是把“关系”给“对象”化. 对应到数据库,我们知道关系数据库(例如Mys ...

  10. 关于python的元类

    当你创建一个类时: class Foo(Bar): pass Python做了如下的操作: Foo中有__metaclass__这个属性吗?如果是,Python会在内存中通过__metaclass__ ...

随机推荐

  1. [转]Raspberry Pi做成路由器

    http://raspjason.blog.51cto.com/8565009/1426561/ 曾经看到很多文章把Raspberry Pi制作成无线AP,但是我今天要做的是把Raspberry Pi ...

  2. 云计算相关的一些概念Baas、Saas、Iaas、Paas

    BaaS(后端即服务:Backend as a Service)公司为移动应用开发者提供整合云后端的边界服务. SaaS(软件即服务:Software as a Service)提供了完整的可直接使用 ...

  3. WIN7,WIN8,WIN8.1,64位客户端使用32位的ODBC配置

    运行64位的ODBC管理器,点开始-->运行-->odbcad32回车即可打开,但打开后看不到32位的驱动, 如果要运行32位的ODBC管理器,该怎么办呢,其实很简单, 只要执行C:\Wi ...

  4. AX2012 R3升级CU8的一些错误

    AX2012 R3安装升级包CU8后进入系统,系统会提示打开软件升级清单“Software update checklist”,清单列出了升级要做的一系列动作. 在进行到编译应用时“Compile a ...

  5. python 二进制读写文件

    #-*- coding: utf-8 -*- f = open('f:/text.bmp','rb') filedata = f.read() filesize = f.tell() f.close( ...

  6. 从抽象谈起(三):AOP编程和ASP.NET MVC

    AOP(Aspect oriented programming)面向切面编程.说成切面不容易理解,代码哪里有切面?又不是三维物体.概念不管,我们从其思想来理解这个名词吧. AOP的主要思想是把相同.相 ...

  7. twisted 学习笔记二:创建一个简单TCP客户端

    #coding=utf-8 from twisted.internet import reactor,protocol class QuickClient(protocol.Protocol): de ...

  8. 自动化测试管理平台ATMS(V2.0.3_8.28)下载

    自动化测试管理平台ATMS(V2.0.3_8.28)下载http://automationqa.com/forum.php?mod=viewthread&tid=2845

  9. 理解WebSocket

    WebSocket的动机是什么? 目前的Web通信使用的是HTTP协议,HTTP协议是基于TCP协议的应用层协议,HTTP协议的工作模式是request/response模式.在一次通信中,必须首先由 ...

  10. Qt编写自定义控件大全

    最新版可执行文件 http://pan.baidu.com/s/1i491FQP 不定期增加控件及修正BUG和改进算法. 总图: 1:动画按钮 * 1:可设置显示的图像和底部的文字 * 2:可设置普通 ...