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有一套规则:

  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 = "[email protected]")
s1.save()
print "-------------------------------------------------"
s2 = Student(id = 1, name = "Wilber", gender = "male")    

代码中通过元类创建Student类,并将类的属性与数据表关联起来:

总结

本文介绍了Python中元类的概念,通过元类可以在运行时创建类。

当用户定义一个类class的时候,Python解释器就会在当前类中查找"__metaclass__"属性,如果找到,就通过该属性对应的代码创建类;如果没有找到,就继续以相同的规则查找父类。如果在任何父类中都找不到"__metaclass__",就会用内置的type来创建类对象。

时间: 2024-10-08 20:15:29

Python中的元类的相关文章

Python中的元类(metaclass)

推荐+收藏:深刻理解Python中的元类(metaclass) 做一些笔记学习学习: 在大多数编程语言中,类就是用来描述如何生成一个对象的代码段,在Python中类也是一个对象,这个(类)对象自身拥有创建对象(类实例)的能力. 因为它的本质是一个对象: 可以将它赋值给一个变量 可以拷贝它 增加属性 作为参数进行传递 可以在运行时动态地创建他们,可以在函数中创建类,只需要使用class关键字即可 当使用class关键字的时候,Python解释器会自动地创建这个对象,Python还提供了手动处理的方

深刻理解Python中的元类

译注:这是一篇在Stack overflow上很热的帖子.提问者自称已经掌握了有关Python OOP编程中的各种概念,但始终觉得元类(metaclass)难以理解.他知道这肯定和自省有关,但仍然觉得不太明白,希望大家可以给出一些实际的例子和代码片段以帮助理解,以及在什么情况下需要进行元编程.于是e-satis同学给出了神一般的回复,该回复获得了985点的赞同点数,更有人评论说这段回复应该加入到Python的官方文档中去.而e-satis同学本人在Stack Overflow中的声望积分也高达6

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

深刻理解Python中的元类(metaclass)以及元类实现单例模式 在看一些框架源代码的过程中碰到很多元类的实例,看起来很吃力很晦涩:在看python cookbook中关于元类创建单例模式的那一节有些疑惑.因此花了几天时间研究下元类这个概念.通过学习元类,我对python的面向对象有了更加深入的了解.这里将一篇写的非常好的文章基本照搬过来吧,这是一篇在Stack overflow上很热的帖子,我看http://blog.jobbole.com/21351/这篇博客对其进行了翻译. 一.理解

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

译注:这是一篇在Stack overflow上很热的帖子.提问者自称已经掌握了有关Python OOP编程中的各种概念,但始终觉得元类(metaclass)难以理解.他知道这肯定和自省有关,但仍然觉得不太明白,希望大家可以给出一些实际的例子和代码片段以帮助理解,以及在什么情况下需要进行元编程.于是e-satis同学给出了神一般的回复,该回复获得了985点的赞同点数,更有人评论说这段回复应该加入到Python的官方文档中去.而e-satis同学本人在Stack Overflow中的声望积分也高达6

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

本文由 伯乐在线 - bigship 翻译 英文出处:stackoverflow 译文:http://blog.jobbole.com/21351/ 译注:这是一篇在Stack overflow上很热的帖子.提问者自称已经掌握了有关Python OOP编程中的各种概念,但始终觉得元类(metaclass)难以理解.他知道这肯定和自省有关,但仍然觉得不太明白,希望大家可以给出一些实际的例子和代码片段以帮助理解,以及在什么情况下需要进行元编程.于是e-satis同学给出了神一般的回复,该回复获得了9

python——深刻理解Python中的元类(metaclass)

译注:这是一篇在Stack overflow上 很热的帖子.提问者自称已经掌握了有关Python OOP编程中的各种概念,但始终觉得元类(metaclass)难以理解.他知道这肯定和自省有关,但仍然觉得不太明白,希望大家可以给出一些实际的例子 和代码片段以帮助理解,以及在什么情况下需要进行元编程.于是e-satis同学给出了神一般的回复,该回复获得了985点的赞同点数,更有人评论说这段 回复应该加入到Python的官方文档中去.而e-satis同学本人在Stack Overflow中的声望积分也

Python中的元类(译)

add by zhj: 这是大stackoverflow上一位小白提出的问题,好吧,我承认我也是小白,元类这块我也是好多次想搞明白, 但终究因为太难懂而败下阵来.看了这篇文章明白了许多,再加下啄木鸟社区的 Python 类型和对象  这篇文章.卧槽, 这简直就是珠联璧合,日月神剑啊,尼玛.终于干掉了元类.翻译时有修改,建议与原文一起看. 原文:http://stackoverflow.com/questions/100003/what-is-a-metaclass-in-python?answe

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

非常详细的一篇深入讲解Python中metaclass的文章,感谢伯乐在线-bigship翻译及作者,转载收藏. 本文由 伯乐在线 - bigship 翻译.未经许可,禁止转载!英文出处:stackoverflow.欢迎加入翻译组. 译注:这是一篇在Stack overflow上很热的帖子.提问者自称已经掌握了有关Python OOP编程中的各种概念,但始终觉得元类(metaclass)难以理解.他知道这肯定和自省有关,但仍然觉得不太明白,希望大家可以给出一些实际的例子和代码片段以帮助理解,以及

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

注:本文原稿来自stackoverflow,原文链接,目前已收获5k高赞. 一.类也是对象 在理解元类之前,你需要先掌握Python中的类.Python中类的概念借鉴于Smalltalk,这显得有些奇特.在大多数编程语言中,类就是一组用来描述如何生成一个对象的代码段.在Python中这一点仍然成立: >>> class ObjectCreator(object): … pass … >>> my_object = ObjectCreator() >>>