python之metaclass+singleton(二)

来源:互联网 发布:阿里云推荐算法 编辑:程序博客网 时间:2024/06/07 16:30

metaclass

本文参考了http://blog.jobbole.com/21351/ 中的一些概念。

metaclass 基本概念

什么是metaclass?
英文解释:A metaclass is defined as “the class of a class”.
中文称metaclass为“元类”,其实就是用来生成类的类,因为在上节中已经介绍了,类也是一个对象,那么这个对象是由谁来创建生成的呢?上节介绍的type可以,所以type就是一个“元类”,就是一个metaclass。

类创建过程

我们在通常定义python中的类时用class关键字完成定义,实质就是默认调用了type这个“元类”,利用上节提到的type创建类的方法。

class A(object):    pass

类A,是一个对象, 这个对象由type()创建而来。python解释器在解读到class关键字,知道是定义类(生成类对象时),对应会去该定义中寻找一个名为__metaclass__的属性,此属性用来指定谁来创建这个类(或者说类对象),如果没有指定,那么调用默认“元类”type创建这个类。完成这个类定义,就生成了一个类对象,这个类对象能够再去实例化自己的对象(instance)。
如果定义类时指定了__metaclass__,也就是说指定了用什么来创建这个类对象,就会在解读到类定义时,调用这个指定的“元类”,创建用户所定义的类。
这就是一个类的实现机制。

元类实现

由以上描述可以看出,一个类要是作为“元类”,他一定要能够创建其他类,就是说能实例化出一个类对象。所以通常“元类”都是从type继承而来。看一个小例子:

class MyMeta(type):    def __new__(meta, name, bases, dct):        print '-----------------------------------'        print "Allocating memory for class", name        print meta        print bases        print dct        return super(MyMeta, meta).__new__(meta, name,                                           bases, dct)    def __init__(cls, name, bases, dct):        print '-----------------------------------'        print "Initializing class", name        print cls        print bases        print dct        super(MyMeta, cls).__init__(name, bases, dct)

MyMeta这个“元类”的__new__方法和__init__方法在MyMeta实例化时候会调用,就是在创建类对象时候会调用。

class MyClass(object):    __metaclass__ = MyMeta    def foo(self, param):        passinstance1 = MyClass()instance2 = MyClass()print '-----------------------------------'print instance1print instance2

这个段代码执行就是用MyClass这个类实例化2个对象,instance1, instance1,而类MyClass是用元类”生成的。运行结果如下:

-----------------------------------Allocating memory for class MyClass<class '__main__.MyMeta'>(<type 'object'>,){'barattr': 2, '__module__': '__main__', 'foo': <function foo at 0x00000000021CDEB8>, '__metaclass__': <class '__main__.MyMeta'>}-----------------------------------Initializing class MyClass<class '__main__.MyClass'>(<type 'object'>,){'barattr': 2, '__module__': '__main__', 'foo': <function foo at 0x00000000021CDEB8>, '__metaclass__': <class '__main__.MyMeta'>}-----------------------------------<__main__.MyClass object at 0x0000000002251F60> <__main__.MyClass object at 0x0000000002251F98>

我们解读下运行结果:
1,解释器在解读到MyClass定义时,就会调用“元类”MyMeta去创建MyClass这个类(类对象)。无论是否有类MyClass的实例instance1或instance2均会执行。

2,先运行__new__(上节解释过)为MyClass类对象分配空间。值得一提的是几个参数meta, name, bases, dct。
meta:__metaclass__属性指定的“元类”; name:类名为class关键字后字符串; bases:是父类; dct:类属性
读者是否发现这个__new__方法和type新建类很相似,就是多了一个meta参数,因为实质就是type。

3,上个new的实质就是分配类对象空间,__init__实质才是对类中一些属性,方法进行绑定。new把自己获取的几个参数继续下传给init。
cls:这个就是new中创建出来类对象,名称就是name(MyClass)

4,再用类MyClass实例化对象时候,不会调用MyMeta。

温馨提示:
细心读者有没有发现,MyMeta定义时,__new__方法第一个参数是meta,而__init__第一个参数是cls。这个和第一节中给出的定义不太一样?在第一节中__new__给出的是cls,__init__中给出是self?我们来细细理解下这里的区别。

我们普通定义的类中的__new__是用来创建一个实例,就是这个类创建出来的对象,因而__new__第一个参数默认传入是这个类(或者说类对象),用cls形参表示。与之相对__init__就是初始化实例,那么这个实例用self指代。

但是“元类”中__new__用传入的类(MyMeta),是个“元类”,这个类很特殊啊,他是用来创建类的,因此用cls表示不是很恰当,用meta表示这个参数。MyMeta这个类创建出来的对象还是一个类(或者说类对象),所以在__init__是,第一参数是这个类对象,因此示例中仍用cls表示。

综上所述,希望大家能理解平时定义类时候给的参数self,就是new出来的对象,你开心可以用s,w任何符号来表示self。

class A(object):    def __init__(s, a):        s.a = a#完全可以

metaclass应用

Django中ORM(Object Relational Mapping)便是利用“元类”实现,在此博客中:
http://www.liaoxuefeng.com/wiki/001374738125095c955c1e6d8bb493182103fac9270762a000/001386820064557c69858840b4c48d2b8411bc2ea9099ba000
给出了一个ORM实现很好的示例,Django中Model实现基本思想和这个类似,读者可以参考上面链接作者给出的示例,理解metaclass的应用。笔者从中受益匪浅。

0 0
原创粉丝点击