Shell's Home

Mar 30, 2011 - 1 minute read - Comments

python源码解析读书笔记(三)——对象和函数

1.mro

算法,自身先入栈,而后按声明顺序继承每个父类的mro,内部对象在最后。简单来说,深度优先,从左向右。

当类对象创建时,会将父类所有函数全部复制过来(很明显,应当是符号复制)。

2.super规则

>>> class A(object):

…     def f(self): print ‘A’

>>> class B(object):

…     def f(self): print ‘B’

>>> class C(A):

…     def f(self): print ‘C’

>>> class D(C, B):

…     def f(self): super(D, self).f()

>>> d = D()

>>> d.f()

C

>>> D.__base__

<class ‘__main__.C’>

>>> D.__bases__

(<class ‘__main__.C’>, <class ‘__main__.B’>)

>>> class A(object):

…     def f(self): print ‘A’

>>> class B(object):

…     def g(self): print ‘B’

>>> class C(A, B):

…     def f(self): super(C, self).g()

>>> c = C()

>>> c.f()

B

>>> C.__mro__

(<class ‘__main__.C’>, <class ‘__main__.A’>, <class ‘__main__.B’>, <type ‘object’>)

super的算法是跟随mro次序,寻找非本类第一个符合名称的函数,调用之。

3.construct

instance = cls.__new__(cls, *args, **kargs)

cls.__init__(instance, *args, **kargs)

4.bound method

>>> class A(object):

…     def f(self): pass

>>> a = A()

>>> a.__class__.__dict__[‘f’]

<function f at 0xb7595454>

>>> a.f

<bound method A.f of <__main__.A object at 0xb75a1e6c>>

>>> a.f.im_self

<__main__.A object at 0xb75a1e6c>

bound method是一个函数对象和一个实例对象的集合。

5.descriptor

>>> class A(object):

…     def __get__(self, obj, cls): return ‘A.__get__ %s %s %s’ % (self, obj, cls)

>>> class B(object):

…     v = A()

>>> b = B()

>>> b.v

“A.__get__ <__main__.A object at 0xb75a1cac> <__main__.B object at 0xb75a1cec> <class ‘__main__.B’>“

某个instance的属性查找顺序为,obj.__dict__,class属性(按照mro顺序)。如果有data descriptor则先于obj.__dict__。

于是,这解释了一个问题。我们定义函数的时候,定义的都是“类函数”,即函数是类的成员。为什么最终函数会变成实例的成员呢?为什么又在调用时会自动产生一个self呢?

实例在查找的时候,会先查找class属性中的descriptor。假定class有成员函数f,当使用obj.f时,首先命中这个函数对象,因为这个对象是一个descriptor。descriptor在取值时,会被调用__get__方法,这一方法有obj参数。于是函数对象的默认__get__返回了一个bound method,其中包含了self和函数对象自身。

这种行为在每次调用时都会发生,因此实例成员函数的性能比unbound method直接写对象要慢。