2018-03-02 python super() 调用机制 和类生成过程分析

super(class, object or type)  不用管第2个参数是self 还是cls. 只是用来类型检查,返回值都是根据第一个参数的MRO 继承顺序作出修改。

super 函数的伪代码如下:

def super(class_name,  self):

    mro  = self.__class__.mro()

return mro[mro.index(class_name) + 1]

super(CurClass, self).__init__()  实则是查询类的继承顺序中CurClass 后的 一个类


__new__ 方法的使用

class object:

@staticmethod

    def __new__(cls, *more):

T.__new__(S,...)  //return a new object with type S, a subType of T

        pass

object.__new__(cls[,...])¶

Called to create a new instance of classcls.__new__()is a staticmethod (special-cased so you need not declare it as such) that takes the classof which an instance was requested as its first argument.  The remainingarguments are those passed to the object constructor expression (the call to theclass).  The return value of__new__()should be the new object instance(usually an instance ofcls).

__new__的return 值 可以写成是父类的返回值(因为可以自动递归到object类中),也可以将object的__new__()出来的实例返回

class Person(object):

    def __new__ (cls, *args, **kw):

        return super(Person,cls).__new__(*args,**kw)

    def __init__(self, *args, **kw):        


当调用Person() 时, 第一个被调用的函数是 __new__ 函数, 然后才是 __init__ 函数

如果要得到当前类的实例, 应当在当前类中的__new__ 函数中调用父类的__new__ 方法。(父类一般为object, object.__new__(cls[,...])方法返回 cls 的新实例,然后调用对象的__init__函数增加其属性)

事实上如果类中没用重写__new__方法, 则调用该类的父类的__new__方法来构建该类的实例,如果该类的父类也没有定义,则此规则追溯到object 的__new__方法中。(该new方法中不接受任何参数,所以下面的代码中new 只传入cls 参数)


总结:


class MyType(type):

    def __call__(cls,*args,**kw):

        obj = cls.__new__(cls,*args,**kw)

        print(dir(obj))## The fact is calling the __new__ function recursively.

        obj.__init__(*args,**kw)

        print(dir(obj))

        return obj

class Foo(metaclass= MyType):

    def __init__(self,*args,**kw):

        self.name = 'name'

    def __new__(cls,*args,**kw):

        print("I am called")

        return super(Foo,cls).__new__(cls)

    def __call__(cls,*args,**kw):

        print("avoid call the type function.")

        return cls.__new__(cls,*args,**kw)

def f1(a,b,c = 3 , *args, **kw):

    print('a = ',a,'b = ',b,'c = ',c,'args = ',args,'kw = ', kw)

if __name__ == '__main__':

    f= Foo(a = 1)

打印结果如下:

I am called

['__call__', '__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__']

['__call__', '__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'name']


当解释器遇到class Foo 关键词时, 调用 meta class中的type.__init__方法创建Foo 类(metaclass 的作用只是重载Type class)

当遇到Foo() 生成实例时,不会调用自身的def __call__函数 (自身的__call__ 是被Foo 的实例调用),而是调用Foo 作为Type 实例的 __call__ 函数, 该函数在metaclass 中指向的Customize type中被定义 (type 是所有类对象的类生成器,object 是所有类对象的父类)

type 中的__call__函数不重写的话,只负责两个事情。

A. 生成Foo 的实例

B. 调用实例的__init__ 方法体

你可能感兴趣的:(2018-03-02 python super() 调用机制 和类生成过程分析)