接python学习笔记(2)
python学习笔记3
- 一、面向对象基础
- 1、理解面向对象
- 2、类和对象
- 3、添加和获取对象属性
- 4、魔法方法
- 5、综合应用
- 二、面向对象-继承
- 1、继承的概念
- 2、单继承
- 3、多继承
- 4、子类重写父类的同名属性和方法
- 5、子类调用父类的同名属性和方法
- 6、多层继承
- 7、super()
- 8、私有属性和私有方法
- 三、面向对象-其他
- 1、面向对象三大特性
- 2、类属性和实例属性
- 3、类方法和静态方法
- 四、异常
- 1、了解异常
- 2、捕获异常
- 捕获指定异常
- 捕获多个指定异常
- 捕获异常描述信息
- 捕获所有异常
- 3、异常的else
- 4、异常finally
- 5、异常的传递
- 6、自定义异常
- 五、模块和包
- 1、了解模块
- 2、导入模块
- 3、制作模块
- 4、模块定位顺序
- 5、_ _all__
- 5、包的使用
- 5.1 了解包
- 5.2 制作包
- 5.3 导入包
- 六、面向对象版学员管理系统
- 1、系统需求
- 2、准备程序文件
- 3、书写程序
一、面向对象基础
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=400self.height=500def 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=widthself.height=heightdef 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=widthself.height=heightdef 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=300def __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+=timeif 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=adressself.area=areaself.free_area=areaself.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.areaelse: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=1def 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):passxiaoming=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):passxiaoming=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初始化位置,所以需要再次调用initMaster.__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初始化位置,所以需要再次调用initMaster.__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:无参数的supersuper().__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初始化位置,所以需要再次调用initMaster.__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=2000def __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=500def __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#定义类方法@classmethoddef get_tooth(cls):return cls.__tooth
wangcai=Dog()
result=wangcai.get_tooth()
print(result)
静态方法
静态方法特点
需要通过装饰器@staticmethod来进行修饰,静态方法既不需要传递类对象也不需要传递实例对象(形参没有self/cls)
静态方法也能够通过实例对象和类对象去访问
静态方法使用场景
当方法中既不需要使用实例对象(如实例对象,实例属性),也不需要使用类对象(如类属性,类方法,创建实例等)时,定义静态方法
取消不需要的参数传递,有利于减少不必要的内存占用和性能消耗
#定义类,定义静态方法
class Dog(object):@staticmethoddef 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:breaktime.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=lengthself.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=nameself.gender=genderself.tel=teldef __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、显示功能菜单-->打印序号和功能对应关系--->静态方法@staticmethoddef 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)breakelse: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}")breakelse: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}")breakelse: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知识如下: