从前面"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有一套规则:

  1. Python解释器会在当前类中查找"__metaclass__"属性对于的代码,然后创建一个类对象
  2. 如果没有找到"__metaclass__"属性,会继续在父类中寻找"__metaclass__属性",并尝试前面同样的操作
  3. 如果在任何父类中都找不到"__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__"属性,可以修改创建的类。也就是说,元类做了下面的事情:

  1. 拦截类的创建
  2. 根据"__metaclass__"对应的代码修改类
  3. 返回修改之后的类

元类的__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中的元类的更多相关文章

  1. Python中的元类(metaclass)

    推荐+收藏:深刻理解Python中的元类(metaclass) 做一些笔记学习学习: 在大多数编程语言中,类就是用来描述如何生成一个对象的代码段,在Python中类也是一个对象,这个(类)对象自身拥有 ...

  2. [转]深刻理解Python中的元类(metaclass)以及元类实现单例模式

    使用元类 深刻理解Python中的元类(metaclass)以及元类实现单例模式 在看一些框架源代码的过程中碰到很多元类的实例,看起来很吃力很晦涩:在看python cookbook中关于元类创建单例 ...

  3. 深刻理解Python中的元类metaclass(转)

    本文由 伯乐在线 - bigship 翻译 英文出处:stackoverflow 译文:http://blog.jobbole.com/21351/ 译注:这是一篇在Stack overflow上很热 ...

  4. 深刻理解Python中的元类(metaclass)

    译注:这是一篇在Stack overflow上很热的帖子.提问者自称已经掌握了有关Python OOP编程中的各种概念,但始终觉得元类(metaclass)难以理解.他知道这肯定和自省有关,但仍然觉得 ...

  5. [转] 深刻理解Python中的元类(metaclass)

    非常详细的一篇深入讲解Python中metaclass的文章,感谢伯乐在线-bigship翻译及作者,转载收藏. 本文由 伯乐在线 - bigship 翻译.未经许可,禁止转载!英文出处:stacko ...

  6. 深刻理解Python中的元类(metaclass)【转】

    译注:这是一篇在Stack overflow上很热的帖子.提问者自称已经掌握了有关Python OOP编程中的各种概念,但始终觉得元类(metaclass)难以理解.他知道这肯定和自省有关,但仍然觉得 ...

  7. 深刻理解Python中的元类(metaclass)以及元类实现单例模式

    在理解元类之前,你需要先掌握Python中的类.Python中类的概念借鉴于Smalltalk,这显得有些奇特.在大多数编程语言中,类就是一组用来描述如何生成一个对象的代码段.在Python中这一点仍 ...

  8. Python中的元类(译)

    add by zhj: 这是大stackoverflow上一位小白提出的问题,好吧,我承认我也是小白,元类这块我也是好多次想搞明白, 但终究因为太难懂而败下阵来.看了这篇文章明白了许多,再加下啄木鸟社 ...

  9. 深入理解Python中的元类(metaclass)

    原文 译注:这是一篇在Stack overflow上很热的帖子.提问者自称已经掌握了有关Python OOP编程中的各种概念,但始终觉得元类(metaclass)难以理解.他知道这肯定和自省有关,但仍 ...

随机推荐

  1. 【POJ 2823】Sliding Window(单调队列/堆)

    BUPT2017 wintertraining(16) #5 D POJ - 2823 题意 给定n,k,求滑窗[i,i+k-1]在(1<=i<=n)的最大值最小值. 题解 单调队列或堆. ...

  2. 【题解】 bzoj3894: 文理分科 (网络流/最小割)

    bzoj3894,懒得复制题面,戳我戳我 Solution: 首先这是一个网络流,应该还比较好想,主要就是考虑建图了. 我们来分析下题面,因为一个人要么选文科要么选理科,相当于两条流里面割掉一条(怎么 ...

  3. 自学Linux Shell11.3-使用变量

    点击返回 自学Linux命令行与Shell脚本之路 11.3-使用变量 Shell脚本的执行通常可以采用以下几种方式: 1):bash script-name或sh script-name(推荐使用) ...

  4. 自学Aruba6.3-账号管理(web页面配置)

    点击返回:自学Aruba之路 自学Aruba6.3-账号管理(web页面配置) 1 管理员账号管理 Configuration---Administrator中 角色名称 说明 root 该角色允许管 ...

  5. 【洛谷P3600】 随机数生成器

    https://www.luogu.org/problem/show?pid=3600#sub (题目链接) 题意 一个$n$个数的序列,里面每个数值域为$[1,X]$.给$q$个区间,每个区间的权值 ...

  6. CF321E Ciel and Gondolas

    题意:给定序列,将其分成k段.如果[l, r]在一段,那么每对不相同的i,j∈[l, r]都会有ai,j的代价.求最小总代价. 解:提供两种方案.第三种去bzoj贞鱼的n²算法. 决策单调性优化: 对 ...

  7. P3747 相逢是问候 欧拉定理+线段树

    巨难!!! 去年六省联考唯一的一道黑牌题,我今天一天从早到晚,把它从暴力15分怼到了90分,极端接近正解了. bzoj上A了,但是洛谷和loj上面就不行.伪正解会T,奇奇怪怪的类正解会WA.. 那么, ...

  8. A1012. The Best Rank

    To evaluate the performance of our first year CS majored students, we consider their grades of three ...

  9. 基于Spring Cloud的微服务入门教程

    (本教程的原地址发布在本人的简书上:http://www.jianshu.com/p/947d57d042e7,若各位看官有什么问题或不同看法请在这里或简书留言,谢谢!) 本人也是前段时间才开始接触S ...

  10. 最短路算法--SPFA+嵌套map

    hdu 2066   #include<iostream> #include<cstdio> #include<cstring> #include<queue ...