Python基础:元类
一、概述
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语句 时,处理步骤如下:
确定元类
mcls
。元类的查找优先级为:- 首先查找 类Foo 是否拥有属性
__metaclass__
- 否则查找 类Foo的父类 是否具有属性
__metaclass__
- 否则查找 类Foo所在模块 是否具有全局变量
__metaclass__
- 否则使用默认元类(经典类:
types.ClassType
;新式类:type
)
- 首先查找 类Foo 是否拥有属性
使用元类
mcls
创建类Foo
。创建语意等价于:def say(self):
print 'hello' # 元类的参数:mcls(name, bases, dict)
Foo = mcls('Foo', (Base,), {'say': say})
创建成功后,类
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基础:元类的更多相关文章
- python基础----元类metaclass
1 引子 class Foo: pass f1=Foo() #f1是通过Foo类实例化的对象 python中一切皆是对象,类本身也是一个对象,当使用关键字class的时候,python解释器在加载cl ...
- 二十六. Python基础(26)--类的内置特殊属性和方法
二十六. Python基础(26)--类的内置特殊属性和方法 ● 知识框架 ● 类的内置方法/魔法方法案例1: 单例设计模式 # 类的魔法方法 # 案例1: 单例设计模式 class Teacher: ...
- python基础——枚举类
python基础——枚举类 当我们需要定义常量时,一个办法是用大写变量通过整数来定义,例如月份: JAN = 1 FEB = 2 MAR = 3 ... NOV = 11 DEC = 12 好处是简单 ...
- python基础——定制类
python基础——定制类 看到类似__slots__这种形如__xxx__的变量或者函数名就要注意,这些在Python中是有特殊用途的. __slots__我们已经知道怎么用了,__len__()方 ...
- Python基础-类的探讨(class)
Python基础-类的探讨(class) 我们下面的探讨基于Python3,我实际测试使用的是Python3.2,Python3与Python2在类函数的类型上做了改变 1,类定义语法 Python ...
- python 通过元类控制类的创建
一.python中如何创建类? 1. 直接定义类 class A: a = 'a' 2. 通过type对象创建 在python中一切都是对象 在上面这张图中,A是我们平常在python中写的类,它可以 ...
- Python 的元类设计起源自哪里?
一个元老级的 Python 核心开发者曾建议我们( 点击阅读),应该广泛学习其它编程语言的优秀特性,从而提升 Python 在相关领域的能力.在关于元编程方面,他的建议是学习 Hy 和 Ruby.但是 ...
- Python之元类详解
一.引子 元类属于Python面向对象编程的深层魔法,99%的人都不得要领,一些自以为搞明白元类的人其实也是自圆其说,点到为止,从队元类的控制上来看就破绽百出,逻辑混乱: 二.什么是元类 一切源自于一 ...
- 谈谈Python中元类Metaclass(二):ORM实践
什么是ORM? ORM的英文全称是“Object Relational Mapping”,即对象-关系映射,从字面上直接理解,就是把“关系”给“对象”化. 对应到数据库,我们知道关系数据库(例如Mys ...
- 关于python的元类
当你创建一个类时: class Foo(Bar): pass Python做了如下的操作: Foo中有__metaclass__这个属性吗?如果是,Python会在内存中通过__metaclass__ ...
随机推荐
- IOS从一个APP跳到另一个APP
以下为跳转到大众点评APP代码如下: NSString *requestUrlString = @"dianping://shopinfo?id=1000"; NSURL *req ...
- CSS3学习笔记--transform中的Matrix(矩阵)
transform: matrix(a,b,c,d,e,f) ,如下图矩阵所示,任意点(x,y,1)经过matrix变化为(ax+cy+e,bx+dy+f,1),由此可以知道,matrix参数与tra ...
- 如何优雅的在MFC中使用cvSetMouseCallback?
MFC与opencv的cvSetMouseCallback用起来感觉很不兼容. 大部分时候,用cvSetMouseCallback也许只是为了获取一个矩形框,或者绘制一个点,或者其它什么简易的图形,通 ...
- struts1的ActionForm的作用域(生命周期)
转自:http://biancheng.dnbcw.info/java/240347.html 今天查找一个问题:我在列表页面添加一个查询条件,然后查询符合条件的数据.查询结果正确.然后我进入其它菜单 ...
- 兼容IE与firefox的css 线性渐变(linear-gradient)
IE系列 filter: progid:DXImageTransform.Microsoft.Gradient(startColorStr='#FF0000',endColorStr='#F9F900 ...
- 使用jQuery开发一个带有密码强度检验的超酷注册页面
在今天的jQuery教程中,我们将介绍如何使用jQuery和其它相关的插件来生成一个漂亮的带有密码强度检验的注册页面,希望大家喜欢! 相关的插件和类库 complexify - 一个密码强度检验jQu ...
- 『WPF』实现拖动文件到窗体(控件)
前言 实现从窗口外部拖文件到窗口内部并自动捕获文件地址. 第一步 开启属性 启用底层Window的AllowDrop属性,添加Drop事件. Drop事件:当你拖动文件到对应控件后,松开触发. 除Dr ...
- UML3
在UML系统开发中有三个主要的模型: 功能模型: 从用户的角度展示系统的功能,包括用例图. 对象模型: 采用对象,属性,操作,关联等概念展示系统的结构和基础,包括类图. 动态模型: 展现系统的内部行为 ...
- 非常简单实用的Python HTTP服务
在做分布式系统应用的时候经常在测试环境上传一个包,或者干嘛的,公司的服务器比较bug,只给ldap权限,每次只能scp到自己的个人目录下,然后才能进到公共账号下去cp,比较麻烦.这时候如果你需要一个简 ...
- ThoughtWorks 2016年第1期DNA活动总结
今天受邀参加了2016年ThoughtWorks公司成都分公司的2016年第一期DNA活动. 什么是DNA? DNA 即 Design And Analysis.设计与分析.这个活动主要是针对产品经理 ...