类与对象深度
鸭子类型和多态
概念
- 动态语言调用实例方法时不检查类型,只要方法存在,参数正确,就可以调用。这就是动态语言的“鸭子类型”,它并不要求严格的继承体系,一个对象只要“看起来像鸭子,走起路来像鸭子”,那它就可以被看做是鸭子。
- 多态的概念即为定义时的类型和运行时的类型不一样,用可迭代对象举例来说,python确认可迭代对象的途径即为确认对象中是否存在__iter__方法,而不在乎它是什么类型的对象,无论是什么类型的对象,只要存在__iter__方法,就可以作为可迭代对象被调用即为多态
实例
- 定义两个列表,使用extend方法对列表a进行拓展,通过查询extend方法源码可知(查询源代码方法为按住ctrl点击该方法),extend需要的是一个可迭代对象传入,因此我们再定义一个元组和一个集合,对列表a进行拓展
- 通过三张图可以看出,无论extend传入的对象是列表还是元组,集合,只要是可迭代对象,都可以实现对列表a的拓展,体现了鸭子类型思想和多态
type和isinstance的区别
区别
- type函数为返回该对象的类型,isinstanc函数是返回该对象是否是指定类型,二者的区别主要在于,type不考虑继承关系,isinstance考虑继承关系
实例
- 定义两个类,其中B类继承自A类,然后将B实例化,查看type和isinstance的区别
- 从上面两张图可以清晰看出type和isinstance的区别,当出现继承关系时,isinstance依然可以查询到继承关系,而type则考虑不到继承关系
类属性和实例属性的查找顺序
查找原理
- 在python2.2之前,类属性的查找顺序为DFS,即为深度优先原理
- 在python2.2之后,改为BFS,即为广度优先原理
- 但这两种方法都存在缺陷,故目前python采用的查找顺序为c3算法,可以通过类名__mro__来查询搜索顺序
实例
- 我们通过定义一个菱形继承关系(A继承B、C,B、C又继承D)和一个U型继承关系(A继承B、C,B继承E,C继承D),通过查看__mro__来看他的查找顺序
python对象的自省机制
概念
- 自省是通过一定的机制查询到对象的内部结构
Python中比较常见的自省(introspection)机制(函数用法)有: dir(),type(), hasattr(), isinstance(),通过这些函数,我们能够在程序运行时得知对象的类型,判断对象是否存在某个属性,访问对象的属性。
实例
- dir()为显示该对象的可用方法
- dict 为显示该对象的当前属性
- hasattr查看该对象是否有指定属性
- 接下来通过代码展示一下具体的用法
super函数
概念
- super函数是用于调用父类的一个方法
- 在单继承时没有问题,当涉及到多继承问题时,就存在一个调用父类顺序的问题
实例
- 通过一个多继承的实例,查看super函数调用父类的顺序
通过结果我们可以发现super调用父类的顺序与查询属性的顺序相同,都是采用C3算法,可以通过__mro__查询到
魔法函数
魔法函数的实质
-
python中有很多的魔法函数,当我们调用某些函数例如str()时,其实就是在调用__str__魔法方法,str只是一个对__str__魔法方法的封装和优化
-
getitem: 定义该内置函数后,类的实例对象可以按列表方式返回元素。
-
str:
- 1:无__repr__的时候,command中的实例对象将返回内存地址,command 中print(instance)将会返会__str__中定义的字符串。
- 2:有__repr__的时候,command中的实例对象instance将返回__repr__中定义的字符串,command 中print(instance)将会返会__str__中定义的字符串。
-
repr: 同样可以返回预先定义的字符串,参见__str__。
__str__, __repr__ ,__getitem__实例
- 这里通过实例来说明__repr__和__getitem__的作用和区别
通过上面的实例可以发现,通过加入__getitem__方法,使得A类可以直接被遍历,__getitem__方法里面的item指的下标,如果返回值没有通过下标,则会一直循环下去