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直接写对象要慢。

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。