魔法函数
魔法函数总览
str 和 repr 魔法方法的区别
都是打印为字符串类型。
但是str是易读 简单明了。
repr 是给开发人员看的,会显示类的类型。
鸭子类型和多态
多态的概念:java 和 c# 是这一类是强类型语言。使用时,比如整数1 需要声明类型 int a = 1 。
而 python崇尚鸭子类型【即弱类型语言,也可以称为动态语言】。即只需要a=1即可不需要写明类型。
在调用实例方法时不检查类型,只要方法存在,参数正确就可以调用,即【一个对象只要看起来像鸭子,走路像鸭子,就能看作鸭子。】这一类型就是鸭子类型。
如下图所示:在实参中传入的参数,只要是可迭代对象就可以运行。【此处即只要长得像可迭代对象即可】
python中的多态:定义时的类型和运行时的类型不一样就是多态。
如图所示:定义的时候为变量数据类型。运行的时候则加上了(),作为函数名的调用info()。这样变成明确这是一个类。比如cat()这个cat类。
面向对象的三大特征:
- 封装
- 继承
- 多态(定义的时候不知道调用的是谁,还有运行的时候才知道调用的是谁。比如a*2,只有运行的时候在知道a代表什么)
抽象基类(abc模块)
抽象基类介绍
抽象基类(abstract base class,ABC模块):抽象基类就是 类里定义了纯虚成员函数 的类。**纯虚函数只是提供了借口,并没有具体实现。**抽象基类不能被实例化(不能创建对象),通常是作为基类供子类继承,子类中重写虚函数,实现具体的接口。
抽象基类就是 定义各种方法而不做具体实现的类 ,任何继承抽象基类的类必须实现这些方法,否则无法实例化。
可以将抽象基类看成是一种方法细节重写的强制提醒。比如:当几个子类都需要拥有同个接口,但相同接口中又有细节是不同的,此时需要每个接口都重写,防止有子类遗漏重写,所以统一继承抽象基类,那么就会强制提醒需要该方法的重写。
issubclass()与isinstance()区别
- issubclass(类名1,类名2):判断类1是否是类2的子类,返回布尔值。
-isinstance(对象,类型):判断对象是否是xx类型。或者判断对象是否与xx相同类型。返回布尔值。
register()方法继承抽象基类
register():定义好的抽象基类通过register方法可以成为其他类的父类。此时其他类在定义的时候不用在形参出继承抽象基类类名。
使用方法:
抽象基类名. register(需继承的子类名)
抽象基类应用场景
·我们去检查某个类中是否有某种方法
例:判断demo中是否含有 len魔法方法:
hasattr(对象, 方法【字符串形式】):判断对象内部是否有属性。返回的对象为布尔值。
判断对象d是否是sized类:通过判断对象d是否是sized的类来判断时候含有_len_方法。
先从collections模块【很多数据类型都封装在该模块中】的abc类型中,导入sized类型。
isinstance(对象,类名):判断对象是否属于什么类,返回布尔值。
当在pycharm中找不到说明文档时:在电脑中找到python的安装路径,在安装的文件夹中找Lib文件夹。
在Lib文件夹下找到collections_abc.py文件。这类文件前面有下划线则代表为隐藏文件,需要显示隐藏文件。之后,pycharm打开即可看。
注意:
抽象基类虽然可以是成为别的类的父类,但是别的类并不会继承抽象基类的方法和属性。
·我们需要强制某个子类必须实现父类的方法
在创建的父类cachebase 以及子类 redisbase后,运行发现调用子类能够顺利运行并且也能调用父类中的方法。但是,如果想要在子类不重写方法的情况下调用父类中的方法,出现异常的方法。
1、直接在父类方法中编写主动抛出异常。
出现没能被调用的异常,只有在子类重写方法,才能结果不出现报错能够正常执行。
2、使用抽象基类方法完成
导入abc模块,再定义一个类。
首先,使用抽象基类的时候,父类不再是继承object 而是导入abc模块后,继承abc.ABCMeta
之后,需要使用abc装饰器。abc.abstractmethod
注意:两种方法中,第一种方法需要访问、调用后才会触发。但是不去访问就不会触发。
而真正的抽象基类则是在实例化的时候就检测出。
抽象基类特点
- 无法实例化
- 继承类必须具有抽象基类指定方法
抽象基类应用场景
- 检查某个类是否有某种方法
- 强制子类必须实现某些方法
使用isinstance和type的区别
isinstance(对象,判断类型【可以是元组形式填写多个】):判断数据类型,返回布尔值。
比如:
a=1
b=‘耗子’
print( isinstance(a,int))或者print( isinstance(a,(int,str)))【元组形式中可以填写多个数据类型,进行选择判断】
某个对象是否属于类或者某个对象是否属于某个父类继承时,数据判断可以使用。
type(对象):判断数据类型,返回说明类型。
单纯的type某对象返回结果为:某对象是属于xx类。
如图所示:
使用type判断对象是否与某类相同【相同内存地址】是只能用is语句进行布尔值判断。但不能考虑继承关系。
没有继承关系的时候可以通过type+is判断对象与类是否相同的内存地址。
但有继承关系时候 type则不能使用,否则必定为False。
小结
- type:不考虑继承关系,返回说明类型
- isinstance:考虑继承关系,返回布尔值
== 和 is 区别
==:值相等(id可不同)
is:id相同
类属性和实例属性
如图所示:
cls_ins :类属性
self.a 和 send.b:实例属性
当用对象去访问,可以访问类属性和实例属性。因为对象是向上查找
而用类名去访问,只能访问类属性。实例属性会报错,因为类不能向下查找。
区分类名与对象名调用:
类名+类属性为重写类属性【覆盖类属性】
对象名+类属性名为封装,即在init自动方法中添加一个self.属性名并赋值。
类属性和实例属性查找顺序
单继承:
当对象有该实例属性的时候,直接输出实例属性。
当对象没有该实例属性的时候,才会向上查找,使用类属性。
类不能向下查找,所以只能访问到类属性。
多继承:
假设继承关系如下图所示,查看查找顺序:
查找顺序:A本身 之后再左边优先原则+一条路走到底【深度优先原则】。
即A BD CE
假设菱形继承查找顺序:
查找顺序:A BC D
遵循广度优先原则。同时可以通过className[类名]._ mro _【c3算法】来查看。
C3算法:mro的使用方式。
根据打印结果的先后顺序代表查找顺序。
python 对象的自省机制
自省:通过一定的机制查询到对象的内部结构。
python中比较常见的自省(introspecton)机制(函数用法)有:
- dir()【对象所拥有的所有属性,考虑到继承的成员】
- type()【数据类型返回说明类型】
- hasattr()【判断类中是否含有某个方法,返回布尔值】
- isinstance()【判断数据类型,返回布尔值】
通过这些函数,我们能够在程序运行时得知对象的类型,判断对象是否存在某个属性,反问对象的属性。
_dict _:适用于对于当前对象的属性,返回字典,{‘属性’:‘属性值’}
dir():适用于对象的所有属性,将查看对象所含有的所有属性包括继承的属性。返回列表形式。
注意:
dict包含在dir中。即dir中返回的结果中包含了dict的结果。
super函数
在多继承的情况下是根据mro顺序查询,单继承的情况下则是根据父类继承方式查询。
super():子类继承父类后在同个方法名中调用父类的方法时使用。
使用方法:super().方法名()
如图所示:
软编码:
super():函数可以替代父类名字。比如当父类曾经叫做one 如果在子类调用使用父类名的话需要one().init()。此时当父类改名为two那么子类中的调用也要将one改成two。容易造成不便,所以直接使用super替代。这样只需要修改子类继承的形参中的父类名。
同时,注意:
父类方法中的形参在继承后使用super的话必须传入一致的形参,可以后续添加新的形参,但是不能删减形参。除非重写。比如,父类one中init方法形参(name,age)。那么子类继承后必须super().init(name,age)。不能是super().init(age)这样会报错。
硬编码:
不使用super去继承父类的方法,而直接使用类名().方法名() 去调用为硬编码,注意传入的形参中self不能少,不然会报错。
注意:
硬编码需要self形参,而软编码不需要传入。
硬编码当父类名修改后,需要调用的类名也要修改。而软编码调用的类名不需要需改。只需要和硬编码都修改继承的父类名。
认识Mixin模式
它其实是一种设计模式(开发者之间的共识)。最好遵守。
继承是一个”is-a”关系。比如轿车类继承交通工具类,因为轿车是一个(“is-a”)交通工具。一个物品不可能是多种不同的东西,因此就不应该存在多重继承。不过有没有这种情况,一个类的确是需要继承多个类呢?
答案是有,我们还是拿交通工具来举例子,民航飞机是一种交通工具,对于土豪们来说直升机也是一种交通工具。对于这两种交通工具,它们都有一个功能是飞行,但是轿车没有。所以,我们不可能将飞行功能写在交通工具这个父类中。但是如果民航飞机和直升机都各自写自己的飞行方法,又违背了代码尽可能重用的原则(如果以后飞行工具越来越多,那会出现许多重复代码)。
怎么办,那就只好让这两种飞机同时继承交通工具以及飞行器两个父类,这样就出现了多重继承。这时又违背了继承必须是”is-a”关系。这个难题该怎么破?
这时候 Mixin 就闪亮登场了。飞行只是飞机做为交通工具的一种(增强)属性,我们可以为这个飞行的功能单独定义一个(增强)类,称之为 Mixin 类。这个类,是做为增强功能,添加到子类中的。为了让其他开发者,一看就知道这是个 Mixin 类,一般都要求开发者遵循规范,在类名末尾加上 Mixin 。
class Vehicle(object):
pass
class PlaneMixin(object):
# planeMixin这个类名 就是Mixin模式,plane为增加功能的类,Mixin为提示这是增加类
def fly(self):
print('I am flying')
# 本质还是多继承
class Airplane(Vehicle, PlaneMixin):
pass