1、python 对象树
python的继承树中的每个节点即一个命名空间,最底下的叶子为对象实例,对象实例通过 __class__ 钩子与上边的类节点连接,类通过__base__钩子与更高的超类连接。位于最顶上的根节点是type元类。
无论属性或者方法,最终都是在命名空间中爬树、进行查找,每个命名空间的存储以字典的形式进行,字典的键为属性或者方法的名称字符串。
每个对象的属性的查找的命名空间顺序 MRO 是固定的,之前可能是DFS 再 BFS,目前是C3算法来实现。C3算法保证了子类永远在父类前面。
super 函数返回MRO顺序的下一个命名空间对象,主要用在多继承当中。
对于经典的菱形继承。
对于obj = D() 站在obj 对象的角度,obj 的mro顺序[D, B, C, A, object].
2、supper 函数
常见的 super 函数的两种用法:
1、第二个参数是一个实例:
super(B, obj) 返回下一个MRO搜索顺序的命名空间,此处的 mro 由obj.__class__ 提供。
2、第二个参数是一个类:
super(B, sometype) 返回下一个MRO搜索顺序的命名空间,此处的 mro 由 sometype 提供。
python3中 super 函数可以直接不带参数。
属性的搜索顺序:
obj.attr
obj.__getattribute__("attr") #进行拦截。
obj.__dict__["attr"] 及父类的.__dict__["attr"] #如果在树中找到
obj.__getattr__("attr") #如果在树中没有定义,即没找到
class D(object):
def __init__(self):
self.test=20
self.test2=21
def __getattribute__(self,name):
if name=='test':
return 0.
else:
return object.__getattribute__(self, name)
#super(D, self).__getattribute__(name)
#super().__getattribute__(name) #python3中可以这样写
注意这里超类使用
通过 self 来正常的获取属性,即使属性不在超类中,解释器开洞!!!这样抛到高层的超类中,也是为了避免无限循环。 __getattribute__
3、静态方法、实例方法、类方法
class Normal: #通过实例对象来调用时有绑定
def func(x):
print("normal")
n = Normal()
n.func() #实例对象来调用,实例对象自动绑定到方法的一个参数
Normal.func(9) #通过类调用,第一个参数可以任意传入
class CM: #通过实例对象和类来调用都需要绑定
@classmethod
def func(x):
print("classMethod")
cm = CM()
cm.func()
CM.func() #实例对象和类自动绑定到第一个参数
class StaticC: #不绑定
@staticmethod
def func(x):
print("staticMethod")
sobj = StaticC()
sobj.func(3)
StaticC.func(3) #不绑定到参数
python的所有方法都可以通过类实例对象和类来调用。对于普通方法而言,通过实例对象来调用,实例对象自动被绑定到第一个参数(约定名称为self),但是通过类来调用,不绑定该参数,所以该参数可以任意传入,没有任何约束。对于类方法,通过实例对象和类来调用,都自动绑定到第一个参数,所以类方法至少需要一个参数。对于静态方法,通过类和实例来调用,不做任何参数绑定,所以所有的参数都需要额外传入。
4、dir() 函数属性获取
__dict__ 只包含每个节点命名空间自身的属性,dir() 则会爬树,从实例爬到类,再爬完所有的父类,但是不包括类所属的类(即元类)。普通类都可以调用 .mro() 方法,但是该方法其实是终极元类 type 所有,包括 __base__,__class__ 都是从 type 元类所来,所以 dir() 列表中没有。
5、type 与 object 的关系
python 中一切都是对象,但是对象有其所属的类。所以存在两种关系:
1、对象与类之间的某个对象是否属于某个类的 isinstance 的关系。
2、类与类之间是否存在继承的 issubclass 的关系。
object 是所有类的父类,所以 issubclass(anyclass, object) 都是 True。type 则是所有类的类,所有 isinstance(anyclass, type)都是 True.
唯一的一个 False 是 issubclass(object, type).