Python中的元类
从前面"Python对象"文章中了解到,在Python中一切都是对象,类可以创建实例对象,但是类本身也是对象。
class C(object):
pass c = C()
print c.__class__
print C.__class__
代码中,通过"__class__"属性来查看对象的类型,对于类C对象本身,它的类型是type。
由于类也是对象,所以就可以在运行时动态的创建类,那么这时候就要用到内建函数type了。
再看type
从前面的文章了解到,可以通过内建函数type来获取对象的类型。
class C(object):
pass c = C()
print c.__class__ is type(c)
print C.__class__ is type(C)
这里,我们就看看内建函数type的另一个强大的功能,动态的创建类。当使用type创建类的时候,有以下形式:
type(类名, 父类的元组(可以为空), 属性的字典)
- 要创建的class的名字
- 父类集合,如果只有一个父类,别忘了tuple的单元素写法
- class的属性字典
看看type创建类的例子:
def printInfo(self):
print "%s is %d years old" %(self.name, self.age) S = type("Student", (object, ), {"name": "Wilber", "age": 28, "printStudentInfo": printInfo}) print type(S)
s = S()
print type(s)
s.printStudentInfo()
例子中,通过type动态的创建了一个Studnent类,并且通过这个类可以创建实例:
__metaclass__
函数type实际上是一个元类,元类就是用来创建类的"模板"。我们可以通过类"模板"创建实例对象,同样,也可以使用元类"模板"来创建类对象;也就是说,元类就是类的类。
在创建一个类的时候,可以设置"__metaclass__"属性来指定元类。
"__metaclass__"属性对应的代码就是创建类的代码(这段代码可以是一个函数,也可以是一个类);如果这段代码是类,"__metaclass__"的类名总是以Metaclass结尾,以便清楚地表示这是一个元类。
对于元类的查找,Python有一套规则:
- Python解释器会在当前类中查找"__metaclass__"属性对于的代码,然后创建一个类对象
- 如果没有找到"__metaclass__"属性,会继续在父类中寻找"__metaclass__属性",并尝试前面同样的操作
- 如果在任何父类中都找不到"__metaclass__",就会用内置的type来创建这个类对象
def queueMeta(name, bases, attrs):
attrs['InQueue'] = lambda self, value: self.append(value) def deQueue(self):
if len(self) > 0:
return self.pop(0)
attrs['DeQueue'] = deQueue # 直接调用type内建函数
return type(name, bases, attrs) # 元类从`type`类型派生
class QueueMetaclass(type):
def __new__(cls, name, bases, attrs):
attrs['InQueue'] = lambda self, value: self.append(value) def deQueue(self):
if len(self) > 0:
return self.pop(0)
attrs['DeQueue'] = deQueue # 直接调用type内建函数
# return type(name, bases, attrs) # 通过父类的__new__方法
return type.__new__(cls, name, bases, attrs) class MyQueue(list):
# 设置metaclass属性,可以使用一个函数,也可以使用一个类,只要是可以创建类的代码
#__metaclass__ = queueMeta
__metaclass__ = QueueMetaclass
pass q = MyQueue("hello World")
print q
q.InQueue("!")
print q
q.DeQueue()
print q
代码中的MyQueue类型继承自list,但是通过设置"__metaclass__"属性,可以修改创建的类。也就是说,元类做了下面的事情:
- 拦截类的创建
- 根据"__metaclass__"对应的代码修改类
- 返回修改之后的类
元类的__init__和__new__
当创建元类的时候,为了定制创建出来的类的特性,一般会实现元类的"__init__"和"__new__"方法。
class MyMetaclass(type):
def __new__(meta, name, bases, attrs):
print '-----------------------------------'
print "Allocating memory for class", name
print meta
print bases
print attrs
return super(MyMetaclass, meta).__new__(meta, name, bases, attrs) def __init__(cls, name, bases, attrs):
print '-----------------------------------'
print "Initializing class", name
print cls
print bases
print attrs
super(MyMetaclass, cls).__init__(name, bases, attrs) class MyClass(object):
__metaclass__ = MyMetaclass def foo(self, param):
pass barattr = 2
通过这个例子演示了使用元类的"__init__"和"__new__"方法:
元类的__call__
"__call__"是另外一个经常在实现元类时被重写的方法,与"__init__"和"__new__"不同的是,当调用"__call__"的时候,类已经被创建出来了,"__call__"是作用在类创建的实例过程。
看下面的代码:
class MyMetaclass(type):
def __call__(cls, *args, **kwds):
print '__call__ of ', str(cls)
print '__call__ *args=', str(args)
return type.__call__(cls, *args, **kwds) class MyClass(object):
__metaclass__ = MyMetaclass def __init__(self, a, b):
print 'MyClass object with a=%s, b=%s' % (a, b) print 'gonna create foo now...'
foo = MyClass(1, 2)
代码的输出为:
元类使用举例
前面已经介绍了很多关于元类的知识了,下面看看怎么实际使用元类。
元类在ORM中是比较常用的,因为需要在运行时创建类型,看下面简单的例子:
class Field(object):
def __init__(self, fname, ftype):
self.fname = fname
self.ftype = ftype
def __str__(self):
return '{%s: (%s, %s)}' % (self.__class__.__name__, self.fname, self.ftype) class StringField(Field):
def __init__(self, fname):
super(StringField, self).__init__(fname, 'varchar(100)') class IntegerField(Field):
def __init__(self, fname):
super(IntegerField, self).__init__(fname, 'bigint') class ModelMetaclass(type):
def __new__(cls, name, bases, attrs):
if name == "Model":
return super(ModelMetaclass, cls).__new__(cls, name, bases, attrs)
else:
mapping = {}
print "Create Model for:", name
for k, v in attrs.items():
if isinstance(v, Field):
print "mapping %s with %s" %(k, v)
mapping[k] = v
attrs['_table'] = name
attrs['_mapping'] = mapping
return type.__new__(cls, name, bases, attrs) class Model(dict):
__metaclass__ = ModelMetaclass def __init__(self, **kwargs):
for key in kwargs.keys():
if key not in self.__class__._mapping.keys():
print "Key '%s' is not defined for %s" %(key, self.__class__.__name__)
return
super(Model, self).__init__(**kwargs) def save(self):
fields = []
params = []
args = []
for k, v in self.__class__._mapping.items():
fields.append(k)
params.append("'{0}'".format(self[k]))
sql = 'insert into %s (%s) values (%s)' % (self.__class__._table, ','.join(fields), ','.join(params))
print 'SQL: %s' %sql class Student(Model):
id = IntegerField('id_c')
name = StringField('username_c')
email = StringField('email_c') print "-------------------------------------------------"
print Student._table
print Student._mapping
print "-------------------------------------------------"
s1 = Student(id = 1, name = "Wilber", email = "wilber@sh.com")
s1.save()
print "-------------------------------------------------"
s2 = Student(id = 1, name = "Wilber", gender = "male")
代码中通过元类创建Student类,并将类的属性与数据表关联起来:
总结
本文介绍了Python中元类的概念,通过元类可以在运行时创建类。
当用户定义一个类class的时候,Python解释器就会在当前类中查找"__metaclass__"属性,如果找到,就通过该属性对应的代码创建类;如果没有找到,就继续以相同的规则查找父类。如果在任何父类中都找不到"__metaclass__",就会用内置的type来创建类对象。
Python中的元类的更多相关文章
- Python中的元类(metaclass)
推荐+收藏:深刻理解Python中的元类(metaclass) 做一些笔记学习学习: 在大多数编程语言中,类就是用来描述如何生成一个对象的代码段,在Python中类也是一个对象,这个(类)对象自身拥有 ...
- [转]深刻理解Python中的元类(metaclass)以及元类实现单例模式
使用元类 深刻理解Python中的元类(metaclass)以及元类实现单例模式 在看一些框架源代码的过程中碰到很多元类的实例,看起来很吃力很晦涩:在看python cookbook中关于元类创建单例 ...
- 深刻理解Python中的元类metaclass(转)
本文由 伯乐在线 - bigship 翻译 英文出处:stackoverflow 译文:http://blog.jobbole.com/21351/ 译注:这是一篇在Stack overflow上很热 ...
- 深刻理解Python中的元类(metaclass)
译注:这是一篇在Stack overflow上很热的帖子.提问者自称已经掌握了有关Python OOP编程中的各种概念,但始终觉得元类(metaclass)难以理解.他知道这肯定和自省有关,但仍然觉得 ...
- [转] 深刻理解Python中的元类(metaclass)
非常详细的一篇深入讲解Python中metaclass的文章,感谢伯乐在线-bigship翻译及作者,转载收藏. 本文由 伯乐在线 - bigship 翻译.未经许可,禁止转载!英文出处:stacko ...
- 深刻理解Python中的元类(metaclass)【转】
译注:这是一篇在Stack overflow上很热的帖子.提问者自称已经掌握了有关Python OOP编程中的各种概念,但始终觉得元类(metaclass)难以理解.他知道这肯定和自省有关,但仍然觉得 ...
- 深刻理解Python中的元类(metaclass)以及元类实现单例模式
在理解元类之前,你需要先掌握Python中的类.Python中类的概念借鉴于Smalltalk,这显得有些奇特.在大多数编程语言中,类就是一组用来描述如何生成一个对象的代码段.在Python中这一点仍 ...
- Python中的元类(译)
add by zhj: 这是大stackoverflow上一位小白提出的问题,好吧,我承认我也是小白,元类这块我也是好多次想搞明白, 但终究因为太难懂而败下阵来.看了这篇文章明白了许多,再加下啄木鸟社 ...
- 深入理解Python中的元类(metaclass)
原文 译注:这是一篇在Stack overflow上很热的帖子.提问者自称已经掌握了有关Python OOP编程中的各种概念,但始终觉得元类(metaclass)难以理解.他知道这肯定和自省有关,但仍 ...
随机推荐
- HNOI2017大佬
贼难的一道题 虽然算法都不难,但组合起来就是想不到 首先,最简单的一步,对所有大佬,嘲讽你减的自信值和你做水题回复自信值都是不变的,写个\(dp\),设\(dp[i][j]\)表示第\(i\)天自信值 ...
- 自学Python5.1-面向对象与面向过程
自学Python之路 自学Python5.1-面向对象与面向过程 面向过程:根据业务逻辑从上到下写代码. 优点:性能比面向对象高,因为类调用时需要实例化,开销比较大,比较消耗资源;比如单片机.嵌入式开 ...
- bzoj1494 生成树计数 (dp+矩阵快速幂)
题面欺诈系列... 因为一个点最多只能连到前k个点,所以只有当前的连续k个点的连通情况是对接下来的求解有用的 那么就可以计算k个点的所有连通情况,dfs以下发现k=5的时候有52种. 我们把它们用类似 ...
- Linux:进程实例信息(/proc)
https://blog.csdn.net/test1280/article/details/73632333 Linux:进程实例信息(/proc) 问几个问题: 1.怎么知道一个进程对应哪个可执行 ...
- hive1.1.0安装
0. 说明 已经安装好Hadoop-1.2.1. 安装好mysql. 1.解压安装包 先把安装包下载.然后解压: tar -zxvf apache-hive-1.1.0-bin.tar.gz 2.配置 ...
- HASH 字符串哈希 映射转化
哈希HASH的本质思想类似于映射.离散化. 哈希,通过给不同字符赋不同的值.并且钦定一个进制K和模数,从而实现一个字符串到一个模意义下的K进制数上. 它的主要目的是判重,用于$DFS$.$BFS$判重 ...
- P1099 树网的核
NOIP 2007 提高第四题. 啊......我还是看了题解才做出来的. 这题乍一看毫无头绪,但是我们spy on一下,暗中观察发现:n才300!随便打暴力水过去啊! 然后,这破题怎么暴力?感觉我的 ...
- typescript泛型(学习笔记非干货)
软件工程中,我们不仅要创建一致的定义良好的API,同时也要考虑可重用性. 组件不仅能够支持当前的数据类型,同时也能支持未来的数据类型, 这在创建大型系统时为你提供了十分灵活的功能. In softwa ...
- 织梦DedeCMS信息发布员发布文章阅读权限不用审核自动开放亲测试通过!
文章发布员在织梦dedecms后台添加文章时却要超级管理员审核,这无疑是增加了没必要的工作. 登录该账号发布文章你会发现该文章显示的是待审核稿件,且并没有生成静态文件,在前台是看不到这篇文章的,而多数 ...
- Prometheus Node_exporter
Node Exporter node_exporter 主要用于 *NIX 系统监控, 用 Golang 编写. 功能对照表 默认开启的功能 名称 说明 系统 arp 从 /proc/net/arp ...