Python学习笔记 8.0 面向对象 与 异常

    科技2022-07-11  109

    面向对象 与 异常

    面向对象(基础)一、理解面向对象二、类和对象1.理解类和对象a)类b)对象 2.面向对象试验方法self 三、添加和获取对象属性1类外面添加对象属性2类外面获取对象属性3类里面获取对象属性 四、 魔法方法1 `__init__()`{前后两端都是双下划线}2`__str__()`{前后两端都是双下划线}3`__del__()`{前后两端都是双下划线} 五、综合应用烤地瓜搬家具 六、重要内容总结1.类2.对象3.获取对象属性4.魔法方法 面向对象—继承(高级)一、继承的概念二、单继承三、 多继承四、 子类重写父类同名方法和属性五、 子类调用父类的同名方法和属性六、 多层继承七、super()调用父类方法八、私有权限1 定义私有属性和方法2 获取和修改私有属性值 九、总结面向对象—继承 面向对象—其他(终章)一、面向对象具有三大特性:1 了解多态 二、类属性和实例属性1 类属性2 修改类属性 三、类方法和静态方法1 类方法2 静态方法 四、面向对象—其他篇总结 异常一、了解异常二、异常的写法1.捕获指定异常2 捕获指定异常3 捕获多个指定异常4 捕获异常描述信息5 捕获所有异常 6 异常的else7 异常的finally 三、异常的传递四、 自定义异常五、异常的总结

    面向对象(基础)

    一、理解面向对象

    面向对象是一种抽象化的编程思想,很多编程语言都有一种的思想。 例如:洗衣服 思考:几种途径可以完成洗衣服? 答: 手洗 和 机洗。 对比发现机洗更简单。 面向对象就是将编程当成是一个事物,对外界来说,事物是直接使用的,不用去管他内部的情况。而编程就是设置事物能够做什么事。

    二、类和对象

    在面向对象编程过程中,有两个重要组成部分:类和对象。 类和对象的关系:用类去创建一个对象。

    1.理解类和对象

    a)类

    类是对一系列具有相同特征和行为的事物的统称,是一个抽象的概念,不是真实存在的事物。 ·0·特征即是属性(变量) ·0·行为即是方法(函数) 类比如实制造洗衣机时要用到的图纸,也就是说类是用来创建对象。

    b)对象

    对象是类创建出来的真实存在的事物,例如:洗衣机。 注意:开发中,先有类,再有对象

    2.面向对象试验方法

    定义类 语法: Class 类名():     代码     …… 注意:类名要满足标识符命名规则,同时遵循大驼峰命名习惯。

    class Washer(): def wash(self): print('能洗衣服') # 2.创建对象 # 对象名 = 类名() haier = Washer() # 3.验证成果 # 打印haier对象 print(haier) # 使用wash功能 -- 实例方法/对象方法 -- 对象名.Wash() haier.wash()

    self

    self指的是调用该函数的对象 谁调用了该函数self指的就是哪个对象 打印self的地址和实例化对象的地址会发现他们两个一样

    一个类可以创建多个对象; 多个对象都调用函数的时候,self地址不相同

    三、添加和获取对象属性

    属性即是特征,比如:洗衣机的宽度,高度,重量…… 对象属性既可以在类外面添加和获取,也能在类里面添加和获取。

    1类外面添加对象属性

    语法: 对象名.属性名 = 值 实例: haier1.height = 500

    2类外面获取对象属性

    语法: 对象名.属性名 实例: print(f’haier1洗衣机的高度是{haier.height}’)

    3类里面获取对象属性

    语法: self.属性名

    class Washer(): def wash(self): print('洗衣服') # 获取对象属性 def print_info(self): # self.属性名 # print(self.height) print(f'洗衣机的高度是{self.height}') haier1 = Washer() # 添加属性 haier1.height = 400 # 对象调用方法 haier1.print_info()

    四、 魔法方法

    在python中,xx()的函数叫做魔法方法,指的是具有特殊功能的函数

    1 __init__(){前后两端都是双下划线}

    __init_()方法的作用:初始化对象。

    class Washer(): def wash(self): print('洗衣服') # 获取对象属性 def print_info(self): # self.属性名 # print(self.height) print(f'洗衣机的高度是{self.height}') haier1 = Washer() # 添加属性 haier1.height = 400 # 对象调用方法 haier1.print_info()

    __init__()方法,在创建一个对象时默认被调用,不需要手动调用 __init__(self)中的self参数,不需要开发者传递,python解释器会自动把当前的对象引用传递过去。 4.1.2 带参数的__init__() 思考:一个类可以创建多个对象,如何对不同的对象设置不同的初始化属性呢? 答:传参数

    class Washer(): # 定义_init_,添加实例属性 def __init__(self, width, height): # 添加实例属性 self.width = width self.height = height def print_info(self): # 类里面调用实例属性 print(f'洗衣机的宽度是{self.width},高度是{self.height}') haier1 = Washer(10, 20) haier1.print_info() haier1 = Washer(30, 40) haier1.print_info()

    2__str__(){前后两端都是双下划线}

    当使用print输出对象的时候,默认打印对象的内存地址。如果类定义了__str__()方法,那么就会打印从在这个方法中return的数据。

    class Washer(): def __init__(self, width, height): self.width = width self.height = height def __str__(self): return '这是海尔洗衣机的说明书' haier1 = Washer(10, 20) print(haier1)

    3__del__(){前后两端都是双下划线}

    当删除对象时,python解释器也会默认调用__del__()方法。

    class Washer(): def __init__(self, weight, height): self.weight = weight self.height = height def __del__(self): print(f'{self}对象已经被删除') haier1 = Washer(10, 20) del haier1

    五、综合应用

    烤地瓜

    1需求 需求主线:

    被烤的时间和对应的地瓜状态: 0-3分钟:生的 3-5分钟:半生不熟 5-8分钟:熟的 超过8分钟:烤糊了

    2.添加的调料: 用户可以按自己的意愿添加调料

    ①步骤分析: 需求涉及一个事物: 地瓜,故案例涉及一个类:地瓜类。

    ②定义类 ·0· 地瓜的属性            被烤的时间            地瓜的状态            添加的调料 ·0· 地瓜的方法            被烤            =用户根据意愿设定每次烤地瓜的时间            =判断地瓜被烤的总时间是在哪个区间,修改地瓜状态 ·0·添加调料            =用户根据意愿设定添加的调料            =将用户添加的调料存储 ·0·显示对象信息

    # 1.定义类:初始化属性,被烤和添加调料的方法,显示对象信息的str class SweetPotato(): def __init__(self): # 被烤的时间 self.cook_time = 0 # 地瓜的状态 self.cook_state = '生的' # 调料列表 self.condiments = [] def cook(self, time): """烤地瓜的方法""" self.cook_time += time if 0 <= self.cook_time < 3: self.cook_state = '生的' elif 3 <= self.cook_time < 5: self.cook_state = '半生不熟' elif 5 <= self.cook_time < 8: self.cook_state = '熟了' elif self.cook_time >= 8: self.cook_state = '烤糊了' def __str__(self): return f'这个地瓜的烤制时间为{self.cook_time},状态是{self.cook_state},添加的调料有{self.condiments}' def add_condiments(self, condiment): """添加调料""" self.condiments.append(condiment) # 2.创建对象并调用对应的实例方法 digua1 = SweetPotato() print(digua1) digua1.cook(2) digua1.add_condiments('辣椒面') print(digua1) digua1.cook(2) print(digua1)

    搬家具

    1需求: 将小于房子 剩余面积的家具摆放到房子中

    2 需求分析 需求涉及到两个事物: 房子 和 家具, 故被案例涉及两个类:房子类 和 家具类。

    ① 定义类 · 0 · 房子类 @实例属性 =房子地理位置 =房子占地面积 =房子剩余面积 =房子内家具列表 @实例方法 =容纳家具 @显示房屋信息 · 0 · 家具类 @家具名称 @家具占地面积 ② 创建对象并调用相关方法

    class Furniture(): def __init__(self, name, area): self.name = name self.area = area class Home(): def __init__(self, address, area): # 地理位置: self.address = address # 房屋面积: self.area = area # 剩余面积 self.free_area =area # 家具列表 self.furniture = [] def __str__(self): return f'房子坐落于{self.address}, 占地面积{self.area}, 剩余面积{self.free_area}, 家具有{self.furniture}' def add_furniture(self, item): """容纳家具""" if self.free_area >= item.area: self.furniture.append(item.name) # 家具搬入后,房屋剩余面积 = 之前剩余面积 - 该家具面积 self.free_area -= item.area else: print('家具太大,剩余面积不足,无法容纳') bed = Furniture('双人床', 6) sofa = Furniture('沙发', 10) # 房子1: 北京, 1000 jia1 = Home('北京', 1000) print(jia1) jia1.add_furniture(bed) print(jia1) jia1.add_furniture(bed) print(jia1)

    六、重要内容总结

    ·面向对象重要组成部分

    1.类

    =创建类 class 类名(): 代码

    2.对象

    对象名 = 类名() =类外面 对象名.属性名 = 值 =类里面 self.属性名 = 值

    3.获取对象属性

    =类外面 对象名.属性名 =类里面 self.属性名

    4.魔法方法

    = __init__():初始化 = __str__():输出对象信息 = __del__():删除对象时调用

    面向对象—继承(高级)

    一、继承的概念

    生活中的继承,一般指的是子女继承父辈的财产。

    class 类名(object): 代码

    Python面向对象的继承指的是多个类之间的所属短息,即子类默认继承父类的所有属性和方法,具体如下:

    # 父类A class A(object): def __init__(self): self.num = 1 def info_print(self): print(self.num) # 子类B class B(A): pass result = B() result.info_print()

    在python中,所有类默认继承object类,obj类是顶级类或基类;其他子类叫做派生类。

    二、单继承

    # 1.师傅类:属性和方法 class Master(object): def __init__(self): self.kongfu = '煎饼果子方法' def make_cake(self): print(f'运用{self.kongfu}制作煎饼果子') # 2.定义徒弟类,继承师傅类 class Prentice(Master): pass # 3.用徒弟类创建对象,调用实例属性和方法 tudi = Prentice() tudi.make_cake()

    三、 多继承

    # 1.师傅类:属性和方法 class Master(object): def __init__(self): self.kongfu = '煎饼果子方法' def make_cake(self): print(f'运用{self.kongfu}制作煎饼果子') # 4. 定义学校类 class School(object): def __init__(self): self.kongfu = '邪法煎饼果子方法' def make_care(self): print(f'运用{self.kongfu}制作煎饼果子') # 2.定义徒弟类,继承师傅类 class Prentice(Master, School): pass # 3.用土地类创建对象,调用实例属性和方法 tudi = Prentice() tudi.make_cake() # 如果一个类继承多个父类,优先继承第一个父类的同名属性和方法

    四、 子类重写父类同名方法和属性

    # 1.师傅类:属性和方法 class Master(object): def __init__(self): self.kongfu = '煎饼果子方法' def make_cake(self): print(f'运用{self.kongfu}制作煎饼果子') # 4. 定义学校类 class School(object): def __init__(self): self.kongfu = '邪法煎饼果子方法' def make_cake(self): print(f'运用{self.kongfu}制作煎饼果子') # 2.定义徒弟类,继承师傅类 和 学校类 , 添加和父类同名的属性和方法 class Prentice(Master, School): # pass def __init__(self): self.kongfu = '正派煎饼果子方法' def make_cake(self): print(f'运用{self.kongfu}方法制作煎饼果子') # 3.用土地类创建对象,调用实例属性和方法 tudi = Prentice() tudi.make_cake() # 如果一个类继承多个父类,优先继承第一个弗雷的同名属性和方法 # 如果子和父类拥有同名属性和方法,子类创建对象调用属性和方法的时候,调用的是子类里面的同名属性和方法

    魔法方法__mro__:显示出一个类的继承顺序: print(Prentice.__mro__)

    五、 子类调用父类的同名方法和属性

    def make_cake(self): # 如果是调用了父类的属性和方法,父类属性会覆盖子类属性,故在调用属性前,先调用自己子类的初始化 self.__init__() # 子类函数再次调用初始化 print(f'运用{self.kongfu}方法制作煎饼果子') # 调用父类方法,但是为保证调用到的也是父类的属性,必须在调用方法前调用父类的初始化 def make_Master_cake(self): Master.__init__(self) Master.make_cake(self) def make_School_cake(self): School.__init__(self) School.make_cake(self) tudi = Prentice() tudi.make_cake() tudi.make_Master_cake() tudi.make_School_cake()

    如果在调用父类的同名方法和属性的时候,没有填入self表示接受则会产生报错。

    缺少位置参数:在调用make_cake函数的时候,没有代表调用对象的参数,需要填入self来表示对象的形参。

    父类再次调用初始化的原因:这里想要调用父类的同名方法和属性,属性在init初始化位置,所以需要再次调用init。

    子类函数再次调用初始化的原因:如果不加自己的初始化,kongfu的属性值是上一次调用的init内的kongfu属性值

    六、 多层继承

    七、super()调用父类方法

    class Master(object): def __init__(self): self.kongfu = '煎饼果子方法' def make_cake(self): print(f'运用{self.kongfu}制作煎饼果子') class School(Master): def __init__(self): self.kongfu = '邪法煎饼果子方法' def make_cake(self): print(f'运用{self.kongfu}制作煎饼果子') # 2.1 super()带参数邪法 # super(School, self).__init__() # super(School, self).make_cake() # 2.2 无参数的super() super().__init__() super().make_cake() class Prentice(School): def __init__(self): self.kongfu = '正派煎饼果子方法' def make_cake(self): # 如果是调用了父类的属性和方法,父类属性会覆盖子类属性,故在调用属性前,先调用自己子类的初始化 self.__init__() print(f'运用{self.kongfu}方法制作煎饼果子') # 调用父类方法,但是为保证调用到的也是父类的属性,必须在调用方法前调用父类的初始化 # ↓只调用Master的方法 def make_master_cake(self): Master.__init__(self) Master.make_cake(self) # ↓只调用School的方法 def make_school_cake(self): School.__init__(self) School.make_cake(self) # ↓一次性调用父类School Master的方法 def make_old_cake(self): # 方法一: 如果定义的类名修改,这里也要修改,麻烦; 代码量庞大, 冗余 # School.__init__(self) # School.make_cake(self) # Master.__init__(self) # Master.make_cake(self) # 方法二:super() # 2.1super(当前类名,self).函数() # super(Prentice, self).__init__() # super(Prentice, self).make_cake() # 2.2 无参数super super().__init__() super().make_cake() tudi = Prentice() tudi.make_old_cake()

    注意:使用super()可以自动查找父类。调用顺序遵循__mro__类属性的顺序。比较适合单继承使用

    八、私有权限

    1 定义私有属性和方法

    在python中,可以为实例属性和方法设置私有权限,即设置某个实例属性或实例方法不继承给子类。 设置私有权限的方法:在属性名和方法名 前面 加上两个下划线_。

    def __init__(self): self.kongfu = '正派煎饼果子方法' self.__money = 1000 def __info_print(self): print('这是私有方法') print(tudi.__money) super().make_cake()

    2 获取和修改私有属性值

    在python中,一般定义函数名get_xx用来获取私有属性,定义set_xx用来修改私有属性值。(工作习惯)

    def get_money(self): return self.__money # 修改私有属性 def set_money(self): self.__money = 500 print(tudi.get_money()) #1000 tudi.set_money() print(tudi.get_money()) #500

    九、总结面向对象—继承

    ·0· 继承的特点 =子类默认拥有父亲的所有属性和方法 =子类重写父类同名方法和属性 =子类调用父类同名方法和属性

    ·0· super()方法快速调用父类方法

    ·0· 私有权限 =不能继承给子类的属性和方法需要添加私有权限 =语法

    class 类名(): # 私有属性 __属性名 =# 私有方法 def __函数名(self): 代码

    面向对象—其他(终章)

    学习目标:

    面向对象三大特性类属性和实例属性类方法和静态方法

    一、面向对象具有三大特性:

    多态封装(面向对象—基础篇)继承(面向对象—继承篇)

    1 了解多态

    多态指的是一类事物有多种形态,(一个抽象类有多个子类,因而多态的概念依赖于继承)

    ·0· 定义:多态十一中使用对象的方式,子类重写父类方法,调用不同子类对象的相同父类方法,可以产生不同的执行结果

    ·0· 好处:调用灵活,有了堕胎,更容易编写出通用的代码,做出通用的编程,以适应需求的不断变化。

    ·0· 实现步骤: = 定义父类,并提供父类方法 = 定义子类,并重写父类方法 = 传递子类对象给调用者,可以看到不用子类执行效果不同

    class Dog(object): def work(self): pass class ArmyDog(Dog): def work(self): print('撕咬敌人') class DrugDog(Dog): def work(self): print('追查毒品') class Person(object): def work_with_dog(self,dog): dog.work() ad = ArmyDog() dd = DrugDog() person = Person() person.work_with_dog(ad) #撕咬敌人 person.work_with_dog(dd) #追查毒品

    二、类属性和实例属性

    1 类属性

    设置和访问类属性 ·0· 类属性就是类对象所拥有的属性,它被 该类的所有实例对象所共有。 ·0· 类属性可以使用类对象或实例对象访问。 类属性的优点    = 记录的某项属性 始终保持一致时,则定义类属性。    = 实例属性 要求 每个对象 为其 单独开辟一份内存空间 来记录数据,而 类属性 为全类所共有,仅占用一份内存,更加节省内存空间。

    2 修改类属性

    类属性只能通过对象修改,不能通过实例对象修改,如果通过实例对象修改类属性,表示的是创建了一个实例属性。

    # 修改类属性 类.类属性 = 值 Dog.tooth = 20 print(ad.tooth) # 20 print(dd.tooth) # 20 print(Dog.tooth) # 20 # 修改实例属性 实例.类属性 = 值 ad.tooth = 100 print(ad.tooth) # 100 print(dd.tooth) # 20 print(Dog.tooth) # 20

    三、类方法和静态方法

    1 类方法

    a) 类方法特点 = 需要用装饰器@classmethod 来标识其为类方法,对于类方法,第一个参数必须是类对象,一般以cls作为第一个参数。

    b) 类方法使用场景 = 类方法中 需要使用类对象(如访问私有类属性等)时,定义类方法 = 类方法一般和类属性配合使用

    # 1. 定义类:私有类属性, 类方法获取这个私有类属性 class Dog(object): __tooth = 10 # 定义类方法 @classmethod def get_tooth(cls): #cls 代表了Dog类 return cls.__tooth # 2.创建对象,调用类方法 wangcai = Dog() result = wangcai.get_tooth() print(result)

    2 静态方法

    a) 静态方法特点 ·0· 需要通过装饰器@staticmethod来进行修饰,静态方法既不需要传递类对象也不需要传递实例对象(形参没有self/cls)。 ·0· 静态方法也能够通过 实例对象 和 类对象 去访问。

    b) 静态方法使用场景 ·0· 当方法中 既不需要使用实例对象(如实例对象,实例属性),也不需要使用类对象(如类属性,类方法,创建实例等)时,定义静态方法。 ·0· 取消不需要的参数传递,有利于 减少不必要的内存占用和性能消耗。

    # 1.定义类,定义静态方法 class Dog(object): @staticmethod def info_print(): print('这是一个静态方法') # 2.创建对象 wangcai = Dog() # 3.调用静态方法: 类 和 对象 wangcai.info_print() # 这是一个静态方法 Dog.info_print() # 这是一个静态方法

    四、面向对象—其他篇总结

    ·0· 面向对象三大特性 =1=封装 =2=继承 =3=多态

    ·0· 类属性 =归属于类对象的属性,所有对象共有的属性

    ·0· 实例属性

    ·0· 类方法

    @classmethod def xx(): 代码

    ·0· 静态方法

    @staticmethod def xx(): 代码

    异常

    一、了解异常

    当检测到一个错误时,解释器就无法继续运行了,反而出现了一些错误的提示,这就是所谓的“异常”。

    二、异常的写法

    1.捕获指定异常

    @语法

    # 需求:尝试打开test.txt(r) ,如果文件不存在,只写方式打开w """ try: 可能发生错误的代码 except: 发生错误的时候执行的代码 """ try: f = open('test.txt', 'r') except: f = open('test.txt', 'w')

    2 捕获指定异常

    @ 语法

    """ try: 可能发生错误的代码 except 异常类型: 如果捕获到该异常类型执行的代码 """ try: print(num) except NameError: print('有错误') # 一般try下方只放一行尝试执行的代码。

    3 捕获多个指定异常

    当捕获多个异常时,可以把要捕获的异常类型的名字,放到except后,并使用元组的方式进行书写。

    try: print(1/0) except (NameError, ZeroDivisionError): print('有错误')

    4 捕获异常描述信息

    try: print(1/0) except (NameError, ZeroDivisionError) as result: print(result) # as 后面的变量存储的是捕获到的异常描述信息

    5 捕获所有异常

    Exception是所有程序异常类的父类。

    try: print(num) except Exception as result: print(result) # name 'num' is not defined

    6 异常的else

    else表示的是如果没有异常要执行的代码

    try: print(1) except Exception as result: print(result) else: print('无异常')

    7 异常的finally

    finally表示的是无论是否异常都要执行的代码。

    三、异常的传递

    体验异常传送

    需求:

    尝试只读方式打开test.txt文件,如果文件存在则读取文件内容,文件不存在则提示用户即可。读取内容要求: 尝试循环读取内容,读取过程中如果检测到用户以外终止程序,则except捕获异常并提示用户。 # 需求1: 尝试只读打开test.txt 文件存在遁去内容,不存在提示用户 # 需求2: 读取内容:循环读取,当无内容的时候退出循环,如果用户意外终止,提示用户已经被意外终止 import time try: f = open('test.txt') # 尝试循环读取内容 try: while True: con = f.readline() # 如果读取完成退出循环 if len(con) == 0: break time.sleep(3) print(con) except: # 在命令提示符中如果按下ctrl+c结束终止的键 print('程序被意外终止') except: print('该文件不存在')

    四、 自定义异常

    在python中,抛出自定义异常的语法为raise异常类对象。 需求:密码长度不足,则报异常(用户输入密码,如果输入的长度不足3位,则报错,即抛出自定义异常,并捕获该异常)。

    五、异常的总结

    ·0· 异常语法

    try: 可能发生异常的代码 except: 如果出现异常执行的代码 else: 没有异常执行的代码 finally: 无论是否异常都要执行的代码

    ·0· 捕获异常

    except 异常类型: 代码 except 异常类型 as xx: 代码

    ·0· 自定义异常

    class 异常类类名(Exception): 代码 # 设置抛出异常的描述信息 def __str__(self)return ……

    ·0· 抛出异常 raise 异常类名()

    ·0· 捕获异常 except Exception……

    Processed: 0.018, SQL: 8