首页 > 代码库 > 奇怪的Pecan class

奇怪的Pecan class

     最近弄了一段时间的ironic,终于把它给调通,可以正常使用了。这两天有时间可以把ironic的api发布流程学习一下,ironic-api发布并不像nova-api那样--自己实现api发布流程,而是采用了轻量级框架pecan。所以就学习下pecan,没想到pecan文档网页被墙了,打不开,只好看源码了。这里并非想阐述pecan框架的实现结构,而只是想探讨下Pecan类的继承和实例化,及引出对__new__调用的实验。

    先看代码:

class PecanBase(object):


class ExplicitPecan(PecanBase):


class Pecan(PecanBase):
    def __new__(cls, *args, **kw):
        if kw.get('use_context_locals') is False:
            self = super(Pecan, cls).__new__(<strong>ExplicitPecan</strong>, *args, **kw)
            print 'use_context_locals'
            self.__init__(*args, **kw)
            return self
        return super(Pecan, cls).__new__(cls)

      按如下方式初始化一个Pecan实例

from pecan import core
p=core.Pecan('ironic.api.controllers.root.RootController')
     这种初始化不会存在什么疑惑,if语句判断结果为不成立,不会执行。直接返回一个Pecan实例。

     如下按照这种方式初始化,p会是什么类的实例呢?

p=core.Pecan('ironic.api.controllers.root.RootController',use_context_locals=False)
     这里传入use_context_locals=False,if判断成立,执行if body。但是这里调用父类的__new__函数很特别,它传入的是ExplicitPecan,而非默认的cls(即Pecan),返回一个ExplicitPecan实例,并调用它的__init__进行初始化。Pecan的__new__函数将返回一个初始化过的ExplicitPecan实例,ExplicitPecan实例没有init_context_local(),那它又怎么继续调用Pecan的__init__呢?
     经过实验证明这里返回值p为ExplicitPecan实例,而非Pecan实例。


做个实验:

class A(object):                                                                
    def __new__(cls, *args):                                                    
        print "A __new__:", cls                                                 
        return super(A, cls).__new__(cls, *args)                                
                                                                                
    def __init__(self, *args):                                                  
        print "A __init__", self                                                
        super(A, self).__init__(*args)                                            
                                                                                  
                                                                                  
class B(A):                                                                       
    def __new__(cls, *args):                                                      
        print "B __new__:", cls                                                   
        return super(B, cls).__new__(cls, *args)                                  
                                                                                  
    def __init__(self, *args):                                                  
        super(B, self).__init__(*args)                                          
        print "B __init__", self                                                
                                                                                
                                                                                
                                                                                
class C(A):                                                                     
    def __new__(cls, *args):                                                    
        print "C __new__:", cls                                                 
        return super(C, cls).__new__(<strong>B</strong>, *args)                                  
                                                                                
    def __init__(self, *args):                                                  
        super(C, self).__init__(*args)                                          
        print "C __init__", self

执行命令及结果:

In [2]: b=testforInit.B()
B __new__: <class 'testforInit.B'>
A __new__: <class 'testforInit.B'>
A __init__ <testforInit.B object at 0x7fb6cdf70150>
B __init__ <testforInit.B object at 0x7fb6cdf70150>

In [3]: c=testforInit.C()
C __new__: <class 'testforInit.C'>
A __new__: <class 'testforInit.B'>

In [4]: print b.__class__<class 'testforInit.B'>In [5]: print c.__class__<class 'testforInit.B'>
     这里可以看到,B按照常规方法调用父类的__new__函数,函数的执行顺序和结果正常。但C调用父类的__new__函数时,传入的是B,而非C。从结果可以看到这样只执行了C和A的__new__函数,返回的是一个B的实例。而A、B、C的__init__函数都未被调用。这里也可以解释了,为什么要在Pecan.__new__的if里面调用ExplicitPecan.__init__函数,否则返回的就是一个未初始化的ExplicitPecan实例了。


奇怪的Pecan class