python学习笔记(3)

接python学习笔记(2)

一、面向对象基础

1、理解面向对象

面向对象就是将编程当成是一个事物,对外界来说,事物是直接使用的,不用去管他内部的情况。而编程就是设置事物能够做什么事情。面向对象就是化简代码用的

2、类和对象

1、什么是类和对象,它们是什么关系?

洗衣机是怎么生产出来的呢?
图纸–>洗衣机–>洗衣服
在面向对象编程过程中,有两个重要组成部分:类和对象
类相当于是图纸,对象相当于是洗衣机
类和对象的关系:用类去创建(实例化)一个对象

2、类

类是对一系列具有相同特征和行为的事物的统称,是一个抽象的概念,不是真是存在的事物。类里面有变量和函数。

对象

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

3、面向对象实现方法
3.1、定义类
语法:

class 类名():
	代码
	......
注意:类名要满足标识命名规则,同时遵循大驼峰命名习惯

3.2、创建对象
语法:

对象名=类名()

3.3、体验类和对象
需求:洗衣服,功能:能洗衣服

#1、定义洗衣机类
class Washer():
    def wash(self):
        print("能洗衣服")
#2、创建对象
#对象名=类名()
haier=Washer()
#3、验证结果
#3.1、打印haier对象
print(haier)
#3.2、使用wash功能---实例方法/对象方法--》用法:对象名.wash()
haier.wash()
结果为:
<__main__.Washer object at 0x0000019A17E52358>
能洗衣服

3.4、类里面的self
上述例子,我们定义函数时,输入小括号直接弹出了self,这个self是什么呢?

self指的是调用该函数的对象

代码如下:

class Waher():
    def wash(self):
        print("洗衣服")
        print(self)     #打印的结果就是haier对象的内存地址
haier=Waher()
print(haier)
haier.wash()
结果为:
<__main__.Waher object at 0x0000022543D42358>
洗衣服
<__main__.Waher object at 0x0000022543D42358>

3.5、一个类创建多个对象
一个类创建多个对象,多个对象都调用函数时,self地址是否相同?
验证代码如下:

class Washer():
    def wash(self):
        print("洗衣服")
        print(self)
haier1=Washer()
haier1.wash()

haier2=Washer()
haier2.wash()
结果为:一个类可以创建多个对象,多个对象都调用函数时,self的值不一样
洗衣服
<__main__.Washer object at 0x00000277DD9652E8>
洗衣服
<__main__.Washer object at 0x00000277DD965358>

3、添加和获取对象属性

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

1、在类外面添加对象属性

语法:对象名.属性名=值

举例:

haier.width=500
haier.height=800

2、在类外面获取对象属性

语法:对象名.属性名
用户想要看见结果,就必须使用print输出结果

代码如下:

haier.width=500
haier.height=800
print("haier洗衣机的宽度是{},高度是{}".format(haier.width,haier.height))
结果为:
haier洗衣机的宽度是500,高度是800

3、在类里面获取对象属性

语法:self.属性名

class Washer():
    def wash(self):
        #类里面获取实例属性
        print(f"haier洗衣机的宽度是{self.width}")
        print(f"haier洗衣机的高度是{self.height}")
#创建对象
haier=Washer()
#添加实例属性
haier.width=500
haier.height=800
haier.wash()
结果为:
haier洗衣机的宽度是500
haier洗衣机的高度是800

4、魔法方法

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

1、_ init_()

作用:用来初始化对象
注意:
1、在创建一个对象时默认被调用,不需要手动调用
2、_ init _(self)中的self参数,不需要开发者传递,python解释器会自动把当前的对象引用传递过去

代码如下:

#目标:定义init魔法方法设置初始化属性并且访问调用
#1、定义类:init魔法方法:width和height;添加实例方法:访问实例属性
class Washer():
    def __init__(self):
        self.width=400
        self.height=500
    def print_info(self):
        print(f"haier洗衣机的宽度为{self.width},洗衣机的高度为{self.height}")
#2、创建对象
haier=Washer()
#3、验证成果
haier.print_info()
结果为:
haier洗衣机的宽度为400,洗衣机的高度为500

2、带参数的_ init _()

一个类可以创建多个对象,如何对不同的对象设置不同的初始化属性呢?
答案为:传参数

代码如下:

class Washer():
    def __init__(self,width,height):
        self.width=width
        self.height=height
    def print_info(self):
        print(f"洗衣机的宽度为{self.width}")
        print(f"洗衣机的高度为{self.height}")

haier1=Washer(30,40)  #创建多个对象且属性值不同
haier1.print_info()   #调用实例方法
print("-"*20)
haier2=Washer(50,60)
haier2.print_info()
结果为:
洗衣机的宽度为30
洗衣机的高度为40
-------------------
洗衣机的宽度为50
洗衣机的高度为60

3、_ str_()

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

代码如下:

class Washer():
    def __init__(self,width,height):
        self.width=width
        self.height=height
    def print_info(self):
        print(f"洗衣机的宽度为{self.width}")
        print(f"洗衣机的高度为{self.height}")
    def __str__(self):
        return "这是海尔洗衣机的说明书"
haier=Washer(100,200)
print(haier)
haier.print_info()
结果为:
这是海尔洗衣机的说明书
洗衣机的宽度为100
洗衣机的高度为200

4、_ del_()

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

代码如下:

class Washer():
    def __init__(self):
        self.width=300
    def __del__(self):
        print("对象已经删除")
haier=Washer()
结果为:
对象已经删除

5、综合应用

需求一:烤地瓜

1、被烤的时间和对应的地瓜状态:
0-3分钟:生的
3-5分钟:半生不熟
5-8分钟:熟的
超过8分钟:烤糊了
2、添加的调料
用户根据自己的意愿添加调料

步骤分析如下:
在这里插入图片描述
实现代码如下:

class SweetPotato():
    def __init__(self):
        #被烤的时间
        self.cook_time=0
        #烤的状态
        self.cook_static="生的"
        #调料列表
        self.condiments=[]
    def cook(self,time):
        """烤地瓜的方法"""
        #之前烤的时间+这次烤的时间
        self.cook_time+=time
        if 0<=self.cook_time<3:
            self.cook_static="生的"
        elif 3<=self.cook_time<5:
            self.cook_static="半生不熟"
        elif 5<=self.cook_time<8:
            self.cook_static="熟了"
        elif self.cook_time>=8:
            self.cook_static="烤糊了"
    def add_condiments(self,condiment):
        """添加调料"""
        self.condiments.append(condiment)
    def __str__(self):
        return f"这个地瓜烤了{self.cook_time}分钟,状态是{self.cook_static},添加的调料有{self.condiments}"

digua=SweetPotato()
digua.cook(4)
digua.add_condiments("蜂蜜")
print(digua)
digua.add_condiments("芥末")
print(digua)

结果为:
在这里插入图片描述
需求二:搬家具

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

步骤分析:

需求涉及两个事物:房子和家具,涉及两个类:房子类和家具类

在这里插入图片描述
实现代码如下:

class Furniture():
    def __init__(self,name,area):
        #家具名字
        self.name=name
        #家具占地面积
        self.area=area
class Home():
    def __init__(self,adress,area):
        self.adress=adress
        self.area=area
        self.free_area=area
        self.furniture=[]
    def __str__(self):
        return f"房子坐落于{self.adress},占地面积为{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("家具太大,房屋剩余面积不足,无法容纳")

jia1=Home("北京",100)
print(jia1)
#可以搬入家具的情况
bed=Furniture("双人床",10)
jia1=Home("北京",100)
jia1.add_furniture(bed)
print(jia1)
#无法搬入家具的情况
sofa=Furniture("沙发",105)
jia1.add_furniture(sofa)
print(jia1)

结果为:
在这里插入图片描述

二、面向对象-继承

1、继承的概念

子类不需要写什么代码,继承父类。作用就是为了化简代码
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()   #结果为:1

在python中,所有类默认继承object类,object类是顶级类或者基类;其他子类叫做派生类(如上述例子的A,B都是派生类)

2、单继承

子类继承父类,默认继承父类里的所有属性及方法

徒弟想要继承师傅的煎饼果子大法

class Master(object):
    def __init__(self):
        self.kongfu='[古法煎饼果子配方]'
    def make_cake(self):
        print(f"运用{self.kongfu}制作煎饼果子")
class Prentice(Master):
    pass

xiaoming=Prentice()
print(xiaoming.kongfu)
xiaoming.make_cake()
结果为:
[古法煎饼果子配方]
运用[古法煎饼果子配方]制作煎饼果子

3、多继承

所谓多继承就是一个子类同时继承了多个父类

小明除了在师傅那里学习了煎饼大法,还在黑马培训班里,包名学习了煎饼大法

class Master(object):
    def __init__(self):
        self.kongfu='[古法煎饼果子配方]'
    def make_cake(self):
        print(f"运用{self.kongfu}制作煎饼果子")
class School(object):
    def __init__(self):
        self.kongfu='[黑马煎饼果子配方]'
    def make_cake(self):
        print(f"运用{self.kongfu}制作煎饼果子")
class Prentice(School,Master):
    pass

xiaoming=Prentice()
print(xiaoming.kongfu)
xiaoming.make_cake()
结果为:
[黑马煎饼果子配方]
运用[黑马煎饼果子配方]制作煎饼果子

结论:当一个类拥有多个父类的时候,默认使用第一个父类的同名属性和方法

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

小明掌握了师傅和黑马培训的煎饼果子技术之后,自己研究出了自己的一套独创煎饼果子配方技术

class Master(object):
    def __init__(self):
        self.kongfu='[古法煎饼果子配方]'
    def make_cake(self):
        print(f"运用{self.kongfu}制作煎饼果子")
class School(object):
    def __init__(self):
        self.kongfu='[黑马煎饼果子配方]'
    def make_cake(self):
        print(f"运用{self.kongfu}制作煎饼果子")
class Prentice(School,Master):
    def __init__(self):
        self.kongfu='[独创煎饼果子配方]'
    def make_cake(self):
        print(f"运用{self.kongfu}制作煎饼果子")

xiaoming=Prentice()
print(xiaoming.kongfu)
xiaoming.make_cake()
结果为:
[独创煎饼果子配方]
运用[独创煎饼果子配方]制作煎饼果子

结论:如果子类和父类拥有同名属性和方法,子类创建对象调用属性和方法的时候,调用的是子类里面的同名属性和方法
拓展:_mro _顺序

可以查看类之间的继承顺序

print(Prentice.__mro__)
结果为:
(<class '__main__.Prentice'>, <class '__main__.Master'>, <class 'object'>)

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

很多顾客都希望能吃到古法和黑马技术的煎饼果子

class Master(object):
    def __init__(self):
        self.kongfu='[古法煎饼果子配方]'
    def make_cake(self):
        print(f"运用{self.kongfu}制作煎饼果子")
class School(object):
    def __init__(self):
        self.kongfu='[黑马煎饼果子配方]'
    def make_cake(self):
        print(f"运用{self.kongfu}制作煎饼果子")
class Prentice(Master,School):
    def __init__(self):
        self.kongfu='[独创煎饼果子配方]'
    def make_cake(self):
        #加自己的初始化的原因:如果不加,会导致kongfu属性值是上一层次调用的init内的kongfu属性值
        self.__init__()
        print(f"运用{self.kongfu}制作煎饼果子")
    #子类调用父类的同名属性和方法,把父类的同名属性和方法再次封装
    def make_master_cake(self):
        #再次调用初始化的原因:这里想要调用父类的同名方法和属性,属性在init初始化位置,所以需要再次调用init
        Master.__init__(self)
        Master.make_cake(self)
    def make_school_cake(self):
        School.__init__(self)
        School.make_cake(self)

xiaoming=Prentice()
xiaoming.make_cake()
xiaoming.make_master_cake()
xiaoming.make_school_cake()
xiaoming.make_cake()

结果为:
在这里插入图片描述

6、多层继承

n年后,小明老了,想要把所有技术传承给自己的徒弟

class Master(object):
    def __init__(self):
        self.kongfu='[古法煎饼果子配方]'
    def make_cake(self):
        print(f"运用{self.kongfu}制作煎饼果子")
class School(object):
    def __init__(self):
        self.kongfu='[黑马煎饼果子配方]'
    def make_cake(self):
        print(f"运用{self.kongfu}制作煎饼果子")
class Prentice(Master,School):
    def __init__(self):
        self.kongfu='[独创煎饼果子配方]'
    def make_cake(self):
        #加自己的初始化的原因:如果不加,会导致kongfu属性值是上一层次调用的init内的kongfu属性值
        self.__init__()
        print(f"运用{self.kongfu}制作煎饼果子")

    #子类调用父类的同名属性和方法,把父类的同名属性和方法再次封装
    def make_master_cake(self):
        #再次调用初始化的原因:这里想要调用父类的同名方法和属性,属性在init初始化位置,所以需要再次调用init
        Master.__init__(self)
        Master.make_cake(self)
    def make_school_cake(self):
        School.__init__(self)
        School.make_cake(self)
#创建徒孙类
class Tunsun(Prentice):
    pass
xiaozhang=Tunsun()
xiaozhang.make_school_cake()
结果为:

7、super()

1、作用

可以快速调用父类方法,可以减少代码的冗余
语法:super(当前类名,self).函数()/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(),想要显示Master里面的内容,就得添加这个代码,调用父类:Master
        #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):
        #加自己的初始化的原因:如果不加,会导致kongfu属性值是上一层次调用的init内的kongfu属性值
        self.__init__()
        print(f"运用{self.kongfu}制作煎饼果子")

    #子类调用父类的同名属性和方法,把父类的同名属性和方法再次封装
    def make_master_cake(self):
        #再次调用初始化的原因:这里想要调用父类的同名方法和属性,属性在init初始化位置,所以需要再次调用init
        Master.__init__(self)
        Master.make_cake(self)
    def make_school_cake(self):
        School.__init__(self)
        School.make_cake(self)
    #一次性调用两个父类
    def make_old_cake(self):
        #方法1(2.1):类名修改比较频繁;代码量庞大,代码冗余
        #School.__init__(self)
        #School.make_cake(self)
        #Master.__init__(self)
        #Master.make_cake(self)

        #方法2(2.2):super(),带参数的super()
        #super(Prentice,self).__init__()
        #super(Prentice,self).make_cake()
        super().__init__()
        super().make_cake()
daqiu=Prentice()
daqiu.make_old_cake()
结果为:
运用[黑马煎饼果子配方]制作煎饼果子
运用[古法煎饼果子配方]制作煎饼果子

注意:使用super()可以自动查找父类。

8、私有属性和私有方法

1、定义私有属性和私有方法
在python中,可以为实例属性和方法设置私有权限,即设置某个实例属性或方法不继承给子类

如果某些属性或方法不想继承给子类,就将这些属性及方法设置为私有属性,方法

小明把技术传承给徒弟的同时,不想把自己的钱传承给徒弟,这个时候就要为钱这个实例属性设置私有权限

设置私有权限的方法:在属性名和方法名前面加上两个下划线_ _

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}制作煎饼果子")

class Prentice(School,Master):
    def __init__(self):
        self.kongfu='[独创煎饼果子配方]'
        #私有属性
        self.__money=2000
    def __info_print(self):
        print("这是私有方法")

class Tunsun(Prentice):
    pass
xiaoqiu=Tunsun()
#print(xiaoqiu.__money) #私有属性也无法访问
xiaoqiu.__info_print()

结果为:
在这里插入图片描述
2、获取和修改私有属性值

注意:私有属性和私有方法只能在类里面访问和修改
在python中,一般定义函数名get_xx用来获取私有属性值,定义set_xx用来修改私有属性值

部分代码如下:

class Prentice(School,Master):
    def __init__(self):
        self.kongfu='[独创煎饼果子配方]'
        #私有属性
        self.__money=2000
    #定义函数,获取私有属性值
    def get_money(self):
        return self.__money
    #定义函数,修改私有属性值
    def set_money(self):
        self.__money=500
    def __info_print(self):
        print("这是私有方法")
class Tunsun(Prentice):
    pass
xiaoqiu=Tunsun()
print(xiaoqiu.get_money())
xiaoqiu.set_money()
print(xiaoqiu.get_money())
结果为:
2000
500

三、面向对象-其他

1、面向对象三大特性

1、封装

将属性和方法书写到类的里面的操作即为封装
封装可以为属性和方法添加私有权限

2、继承

子类默认继承父类的所有属性和方法
子类可以重写父类属性和方法,拥有自己的属性和方法

3、多态

传入不同的对象,产生不同的结果

了解多态

多态指的是一类事物有多种形态(一个抽象类有多个子类,因而多态的概念依赖于继承)
好处:不同的子类对象调用相同的父类方法,调用灵活,有了多态,更容易编写出通用的编程,以适应需求的不断变化

实现步骤:

1、定义父类,提供公共方法
2、定义子类,重写父类方法
3、传递子类对象给调用者,可以看到不同子类执行效果不同

体验多态
需求:警务人员和警犬一起工作,警犬分两种:追击敌人和追击毒品,携带不同的警犬,执行不同的工作

class Dog(object):
    #父类提供唯一的方法,哪怕是空方法
    def work(self):
        print("指哪打哪")
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()
daqiu=Person()
daqiu.work_with_dog(dd)

2、类属性和实例属性

类属性

类属性就是类对象所拥有的属性,它被该类的所有实例对象所共有
类属性可以使用类对象实例对象访问

#定义类,定义类属性
class Dog(object):
    tooth=10
#创建对象
wangcai=Dog()
xiaohei=Dog()
#访问类属性:类和对象分别访问
print(Dog.tooth)
print(xiaohei.tooth)

类属性的优点:

记录的某项数据始终保持一致时,则定义类属性
实例属性要求每个对象为其单独开辟一份内存空间来记录数据,而属性为全类所共有,仅占用一份内存,更加节省内存空间

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

#定义类,定义类属性
class Dog(object):
    tooth=10
#创建对象
wangcai=Dog()
xiaohei=Dog()
#修改类属性,通过类
Dog.tooth=12
print(Dog.tooth)
print(xiaohei.tooth)
结果为:12   12

#测试通过对象修改类属性
wangcai.tooth=13
print(Dog.tooth)
print(wangcai.tooth)
print(xiaohei.tooth)
结果为:
10
13
10

3、类方法和静态方法

类方法
类方法特点

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

类方法使用场景

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

#定义类,私有类属性,类方法获取这个私有类属性
class Dog(object):
    __tooth=10
    #定义类方法
    @classmethod
    def get_tooth(cls):
        return cls.__tooth
wangcai=Dog()
result=wangcai.get_tooth()
print(result)

静态方法
静态方法特点

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

静态方法使用场景

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

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

四、异常

1、了解异常

异常就是我们python编程中运行代码之后遇到的错误

异常的写法

try:
	可能发生错误的代码
except:
	如果出现异常执行的代码

体验案例
需求:尝试以r模式打开文件,如果文件不存在,则以w方式打开

try:
    f=open("test.txt","r")
except:
    f=open("test.txt","w")

了解异常类型
冒号前面的就是异常类型,冒号后面的就是异常描述信息
在这里插入图片描述

2、捕获异常

捕获指定异常

语法

try:
	可能发生错误的代码
except 异常类型:
	如果捕获到该异常类型执行的代码

代码体验
尝试打印num,捕获异常类型为NameError,如果捕获到这个异常类型,执行打印:有错误

try:
    print(num)
except NameError:
    print("有错误")

结果为:
在这里插入图片描述
如果异常类型不正确

try:
    print(1/0)
except NameError:
    print("有错误")

结果为:
在这里插入图片描述
注意:

1、如果尝试执行的代码的异常类型和要捕获的异常类型不一致,则无法捕获异常
2、一般try下方只放一行尝试执行的代码

捕获多个指定异常

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

使用场景

当尝试执行某个代码,并不确定代码的异常类型具体是哪一个,但大概知道是哪几个异常类型

体验:

try:
    print(1/0)
except (NameError,ZeroDivisionError):
    print("有错误")
结果为:
有错误

捕获异常描述信息

异常描述信息包含了具体错误信息,可以帮助我们去定位错误

try:
    print(num)
except (NameError,ZeroDivisionError) as result:
    print(result)

结果为:
在这里插入图片描述

捕获所有异常

以上我们写的代码会发现,还要意识到是哪一个异常类型,如果我们记不清楚是哪一个异常类型怎么办呢,就出现了捕获所有异常
Exception是所有程序异常类的父类

try:
    print(num)
except Exception as result:
    print(result)
结果就是异常描述信息

3、异常的else

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

try:
    print(1)
except Exception as result:
    print(result)
else:
    print("我是else,当没有异常的时候,执行的代码")

结果为:
在这里插入图片描述

4、异常finally

finally表示的是无论是否异常都要执行的代码,例如关闭文件

尝试以r打开一个文件,如果有异常,就用w打开文件,最后关闭文件

try:
    f=open("1.txt","r")
except Exception as result:
    f=open("1.txt","w")
else:
    print("没有异常,真开心")
finally:
    f.close()
结果就会创建一个新文件1.txt

5、异常的传递

需求:

1、尝试只读方式打开test.txt文件,如果文件存在则读取文件内容,文件不存在则提示用户即可
2、读取内容要求:尝试循环读取内容,读取过程中如果检测到用户意外终止程序,则except捕获异常并提示用户

import time
try:
    f=open("test.txt")
    #尝试循环读取内容
    try:
        while True:
            content=f.readline()
            if len(content)==0:
                break
            time.sleep(2)
            print(content)
    except:
        #命令提示符如果按下了ctrl+c,就表示终止结束
        print("程序被意外终止")
    finally:
        f.close()
        print("关闭文件")
except:
   print("该文件不存在")

6、自定义异常

自定义异常就是用来报错,报的是不符合程序逻辑要求的错误
在python中,抛出自定义异常的语法为raise异常类对象

基本语法:

1、自定义异常类
calss 异常类类名(Exception):
	代码
	#设置抛出异常的描述信息
	def __str__(self):
		return ...
2、抛出异常
raise 异常类名()
3、捕获异常
except Exception as result ...

需求:密码长度不足,则异常报错(用户输入密码,如果输入的长度不足3位,则报错,即抛出自定义异常,并捕获该异常)

#自定义异常类,继承Exception
class ShortInputError(Exception):
    def __init__(self,length,min_len):
        self.length=length
        self.min_len=min_len

    #设置抛出异常的描述信息
    def __str__(self):
        return f"你输入的长度是{self.length},密码长度不能少于{self.min_len}个字符"

def main():
    #抛出异常,尝试执行,用户输入密码,如果长度小于3,就抛出异常
    try:
        passwd=input("请输入密码:")
        if len(passwd)<3:
            #raise为抛出异常类对象,抛出异常类创建的对象
            raise ShortInputError(len(passwd),3)   相当于print对象(),就打印出str的内容
    #捕获该异常
    except Exception as result:
        print(result)
    else:
        print("密码已经输入完成")
main()

输入错误,结果为:
在这里插入图片描述
输入正确的情况是:
在这里插入图片描述

五、模块和包

1、了解模块

python模块(Module),是一个python文件,以.py结尾,包含了python对象定义和python语句
模块能定义函数,类和变量,模块里也能包含可执行的代码

下图就是我们平常使用的random模块
在这里插入图片描述

2、导入模块

2.1 导入模块的方式

  • import 模块名
  • from 模块名 import 功能名
  • from 模块名 import *
  • import 模块名 as 别名
  • from 模块名 import 功能名 as 别名

2.2 导入方式详解
2.2.1 、import
语法:

#1、导入模块
import 模块名
import 模块名1,模块名2...

#2、调用功能
模块名.功能名()

需求:基于math模块下的aqrt(),用于开平方计算

import math  #导入模块
print(math.sqrt(9))  #调用sqrt功能
结果为:3.0

2.2.2 、from…import…

语法:from 模块名 import 功能1,功能2,功能3

from math import sqrt
print(sqrt(16))
结果为:4.0

2.2.3 、from…import *

from math import *
print(sqrt(81))
结果为:9.0

2.2.4、as 定义别名
语法与体验

#1、模块定义别名
import 模块名 as 别名
import time as tt
tt.sleep(2)
print("hello")

#2、功能定义别名
from 模块名 import 功能 as 别名
from time import sleep as sl
sl(2)
print("hello")

3、制作模块

在python中,每个python文件都可以作为一个模块,模块的名字就是文件的名字。也就是说自定义模块名必须要符合标识符命名规则

自己制作模块的作用:当python中的模块已经无法满足我们的要求,我们需要频繁使用包含类,函数,变量的代码,不需要频繁的粘贴,只需要做成模块,在需要的地方导入即可,解决了代码冗余。
3.1 定义模块
新建一个python文件,命名为my_module1.py,并定义testA函数
需求:一个函数完成任意两个数字的加法运算

def testA(a,b):
	print(a+b)

3.2 测试模块
在实际开发中,开发人员会自行在py文件中添加一些测试信息,为了让模块能够在项目中达到想要的效果
测试信息要保留,但是如果调用模块文件,测试信息就会被导入在正式结果里,解决方案如下:

def testA(a,b):
    print(a+b)
#当前文件print(__name__)的值为__main__,
#如果在其他导入模块的文件里,print(__name__)的值就是导入的模块名,所以我们用此来做区别
#只在当前文件中调用该函数,其他导入的文件内不符合该条件,则不执行testA函数调用
if __name__=="__main__":
    testA(1,9)

注意:_ name_是系统变量,是模块的标识符,如果是自身模块,值是__main_,否则,是当前模块的名字

验证结果如下:
在这里插入图片描述
导入模块,就会导入模块文件里所有的代码
在这里插入图片描述
3.3 调用模块

import my_module1
my_module1.testA(1,3)
结果为:4

4、模块定位顺序

当导入一个模块,python解析器对模块位置的搜索顺序是:

  • 当前目录
  • 如果不在当前目录,python则搜索在shell变量PYTHONPATH下的每个目录
  • 如果都找不到,Python会查看默认路径,unix下,默认路径一般为/usr/local/lib/python

注意:

  • 自己的文件名不要和已有模块名重复,否则导致模块功能无法使用
  • 使用from模块名import功能的时候,如果功能名字重复,调用到的是最后定义或导入的功能

5、_ all_

如果一个模块文件中有_all__变量,当使用from xxx import *导入时,只能导入这个列表中的元素
my_module1模块代码

#定义多个功能,将某个功能添加到_all_里
__all__=["testA"]
def testA():
    print("testA")
def testB():
    print("testB")

导入模块的文件代码

from my_module1 import *
testA()
testB()

结果为:
在这里插入图片描述

5、包的使用

5.1 了解包

包将所有联系的模块组织在一起,即放到同一个文件夹下,并且在这个文件夹创建一个名字为_init_.py文件,那么这个文件夹就称之为包

5.2 制作包

[New]-[Python Package]-输入包名-[OK]-新建功能模块(有联系的模块)

注意:新建包后,包内部会自动创建_init_.py文件,这个文件控制着包的导入行为,如下图
在这里插入图片描述

快速体验:

1.新建包mypackage
2.新建包内模块:my_module1和my_module2
3.模块内代码如下

#my_module1
print(1)
def ingo_print1():
    print("my_module1")

#my_module2
print(2)
def info_print2():
    print("my_module2"

5.3 导入包

方法一:

import 包名.模块名
包名.模块名.目标

代码如下:

#导入mypackage包下的模块1,使用这个模块内的info_print1函数
import mypackage.my_module1
mypackage.my_module1.info_print1()

方法二:

from 包名 import *
模块名.目标

注意:必须在_init_.py文件中添加_all_=[],控制允许导入的模块列表

代码如下:

from mypackage import *
my_module2.info_print2()

_init_.py里的内容如下:
__all__=["my_module2"]
结果为:
2
my_module2

六、面向对象版学员管理系统

1、系统需求

使用面向对象编程思想,完成学员管理系统的开发,具体如下:

系统要求:学员数据存储在文件中
系统功能:添加,删除学员,修改,查询学员信息,显示所有学员信息,保存学员信息及退出系统等功能

2、准备程序文件

2、1 角色分析
1、学员
2、管理系统

工作中注意:
1、为了方便代码维护,一般一个角色一个程序文件
2、项目要有主程序入口,习惯为main.py

2、2 创建程序文件
创建项目目录,例如:StudentManagerSystem

程序文件如下
程序入口文件:main.py
学员文件:student.py
管理系统文件:managerSystem.py
在这里插入图片描述

3、书写程序

3.1 定义学员类-student.py
需求:

学员信息包含:姓名,性别,手机号
添加_str_魔法方法,方便查看学员对象信息

代码如下

class Student(object):
    def __init__(self,name,gender,tel):
        self.name=name
        self.gender=gender
        self.tel=tel
    def __str__(self):
        return f"该学员的姓名为{self.name},性别为{self.gender},电话号码是{self.tel}"

3.2 定义管理系统类-managerSystem.py
需求:

存储数据的位置:文件(student.data)
加载文件数据
修改数据后保存到文件
存储数据的形式:列表存储学员信息
**系统功能:**添加学员,删除学员,修改学员,查询学员信息,显示所有学员信息,保存学员信息

需求:系统功能循环使用,用户输入不同的功能序号,执行不同的功能

保存学员信息:将修改后的学员数据保存到存储数据的文件里
步骤
打开文件;文件写入数据;关闭文件
文件内数据要求的数据类型是什么?应该为字符串

拓展:_ dict_

收集类对象或实例对象的属性和方法,以及对应的值,从而返回一个字典

代码如下:

from student import *
class StudentManager(object):
    def __init__(self):
        #存储学员数据-->列表
        self.student_list=[]
    #一、程序入口函数
    def run(self):
        #1、加载文件里面的学员数据
        self.load_student()
        while True:
            #2、显示功能菜单
            self.show_menu()
            #3、用户输入功能序号
            menu_num=int(input("请输入您需要的功能序号"))
            #4、根据用户输入的序号执行不同的功能
            if menu_num==1:
                #添加学员
                self.add_student()
            elif menu_num==2:
                #删除学员
                self.del_student()
            elif menu_num==3:
                #修改学员信息
                self.modify_student()
            elif menu_num==4:
                #查询学员信息
                self.search_student()
            elif menu_num==5:
                #显示所有学员信息
                self.show_student()
            elif menu_num==6:
                #保存学员信息
                self.save_student()
            elif menu_num==7:
                #退出系统
                break
    #二、系统功能函数
    #1、显示功能菜单-->打印序号和功能对应关系--->静态方法
    @staticmethod
    def show_menu():
        print("请选择如下功能:")
        print("1:添加学员")
        print("2:删除学员")
        print("3:修改学员信息")
        print("4:查询学员信息")
        print("5:显示所有学员信息")
        print("6:保存学员信息")
        print("7:退出系统")
    #2、添加学员
    def add_student(self):
        #1、让用户输入姓名,性别,手机号
        name = input("请输入您的姓名")
        gender = input("请输入您的性别")
        tel = input("请输入您的手机号")
        #2、创建学员对象--->类,类在student.py里-->先导入student模块,再创建对象
        student=Student(name,gender,tel)
        #3、将该对象添加到学员列表里
        self.student_list.append(student)
        print(self.student_list)
        print(student)
    #3、删除学员
    def del_student(self):
        del_name=input("请输入要删除的学员姓名")
        for i in self.student_list:
            if del_name==i.name:
                self.student_list.remove(i)
                break
        else:
            print("查无此人")
        print(self.student_list)
    #4、修改学员信息
    def modify_student(self):
        modify_name=input("请输入要修改的学员姓名")
        for i in self.student_list:
            if i.name==modify_name:
                i.name=input("请修改学员姓名")
                i.gender=input("请修改学员性别")
                i.tel=input("请修改的手机号")
                print(f"修改学员信息成功,姓名:{i.name},性别{i.gender},手机号{i.tel}")
                break
        else:
            print("查无此人")
    #5、查询学员信息
    def search_student(self):
        search_name=input("请输入要查询的学员姓名")
        for i in self.student_list:
            if i.name==search_name:
                print(f"学员的姓名为{i.name},性别为{i.gender},手机号为{i.tel}")
                break
        else:
            print("查无此人")
    #6、显示所有学员信息
    def show_student(self):
        print("姓名\t性别\t电话")
        for i in self.student_list:
            print(f"{i.name}\t{i.gender}\t{i.tel}")
    #7、保存学员信息
    def save_student(self):
        #1、打开文件
        f=open("student.data","w")
        #2、文件写入学员数据
        #注意:文件写入的数据不能是学员对象的内存地址,需要把学员数据转换为列表字典数据再做存储
        #学员对象的列表转换为字典
        new_list=[i.__dict__ for i in self.student_list]
        print(new_list)
        #注意:文件内数据要求为字符串类型,故需要先转换数据类型
        f.write(str(new_list))
        #关闭文件
        f.close()
    #8、加载学员信息
    def load_student(self):
        #尝试以"r"模式打开数据文件,文件不存在就提示用户;文件存在(没有异常)则读取数据
        try:
            f=open("student.data","r")
        except:
            f=open("student.data","w")
        else:
            #读取数据
            data=f.read()
            #文件中读取的数据都是字符串且字符串为字典数据,故需要转换数据类型再转换字典为对象后存储到学员列表里
            new_list=eval(data)
            self.student_list=[Student(i["name"],i["gender"],i["tel"]) for i in new_list]
        finally:
            #关闭文件
            f.close()

3.3 程序入口文件-main.py

入口文件就是用户登录系统,需要run运行代码的文件

#导入managerSystem模块
from managerSystem import *

#启动学员管理系统
#保证是当前文件运行才能启动管理系统,创建对象并调用run方法
if __name__=="__main__":
    student_manager=StudentManager()
    student_manager.run()

总结:
此次代码用到的python知识如下:

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值