面向对象三大特性:封装、继承、多态
1. 多态
- 概念:在面向对象的编程思想中,一个类可以创建多个对象,每个对象和属性的行为之间会存在一些差异,编程过程中使用不同的对象,那么有可能得到不同的结果
-
优点:提高代码灵活性
class Dog(): def work(self): print('ready to work!') class ArmyDog(Dog): def work(self): Dog.work(self) print('开始抓人了!') class DrugDog(Dog): def work(self): Dog.work(self) print('开始检查毒品!') class Person(): def work_with_dog(self, dog): dog.work() # 多态 ad = ArmyDog() dd = DrugDog() p = Person() p.work_with_dog(ad) p.work_with_dog(dd)
2. 类属性和实例属性
- 类属性
- 类拥有的属性,被该类的所有实例共有;
- 类属性可以使用类对象和实例对象访问;
- 类属性只能通过类对象修改,不能通过实例修改
- 如果通过实例对象修改类属性,表示创建了一个同名实例属性
- 优点:始终保持一致,并只占用一分内存,更加节省内存空间;
class Person(): # 类属性 tooth = 10 # 类私有属性 __leg = 2 def print_info(self): pass # 类属性可以使用类对象和实例对象访问; p = Person() p1 = Person() print(Person.tooth) print(p.tooth) print(p1.tooth) # 类属性只能通过类对象修改,不能通过实例修改 Person.tooth = 20 print(Person.tooth) print(p.tooth) print(p1.tooth) # 如果通过实例对象修改类属性,表示创建了一个同名实例属性 p.tooth = 15 print(Person.tooth) print(p.tooth) print(p1.tooth)
3. 类方法和静态方法
- 类方法: 通过@classmethod装饰器进行装饰的方法,传入的是类对象
- 操作类属性/私有类属性方式时才使用
- 类对象和实例对象都可以使用
- 静态方法:通过@staticmethod装饰器进行装饰的方法
- 形参没有cls/self, 不需要传递类对象和实例对象
- 减少不必要的内存消耗
- 类方法 VS 静态方法
- 定义方式不一样
- 指定形参不一样
- 使用场景不一样
- 类方法修改类属性或者类的其他操作
- 静态方法不需要对象参与的功能实现
- 类和实例都可以调用类方法、静态方法和实例方法
class Person(): __leg = 2 @classmethod def get_leg(cls): return cls.__leg @staticmethod def print_info(): return 'static method' p = Person() print(Person.get_leg()) print(p.get_leg()) print(Person.print_info()) print(p.print_info())
4. 异常
- 概念:在程序运行过程中报的错误
- 异常会影响程序后续代码的运行
- try except 捕获的错误,可以用as为它起别名
-
try except 只能捕获runtime产生的异常
# 捕获异常的完整语句 try: print(num) except (NameError, ZeroDivisionError) as e: print(e) else: print('try未产生异常时,会执行到') finally: print('不管是否出现异常,都会执行到')
-
自定义异常要继承自Exception类,通过raise抛出异常
class InputException(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}' if __name__ == '__main__': min_len = 3 password = input('请输入密码:') try: if len(password) < min_len: raise InputException(len(password), min_len) except Exception as e: print(e) else: print('密码设置完成!')
- 常见的异常类型:
- IOError:读写异常,主要是指要打开的文件不存在的错误提示
- AttributeError:属性异常,特性引用和赋值失败时会引发属性错误
- ImportError:导入了不存在的模块或功能
- IndentationError:缩进错误
- IndexError:索引错误,访问了不存在的数组索引
- KeyError:访问了字典中不存在的key
- SyntaxError:使用了错误的语法
- NameError:试图访问的变量名不存在
5. 模块和包
- 模块就是python文件,以.py结尾,包含python对象和语句,定义了函数,类和变量,模块里也包含可执行代码;
-
模块导入的三种方式:
import 模块名 from 模块名 import 功能名 from 模块名 import * # 为什么使用别名? # 1. 模块名太长 # 2. 与自己定义的模块同名时,避免冲突和混淆 # 定义别名后,只能使用别名 import 模块名 as 别名 from 模块名 import 功能名 as 别名
-
python 常用的标准库: random,time,math,datetime,matplotlib,numpy,pandas,sys,os,requests,threading
- 制作模块
- __name__变量:以当前文件运行时,它的值为__main__,当它被当作模块导入到其他模块时,它的值时所在的模块名
- __all__变量:当模块功能函数被以from 模块名 import * 下使用,只能导入all列表中的功能
__all__ = ['add'] def add(a, b): sum = a + b print(str(sum)) def product(a, b): pro = a * b print(str(pro)) if __name__ == '__main__': add(10,10) product(10,10)
from Day03.MyModule import * # 正常输出 add(10,10) # name 'product' is not defined product(10,10)
- Python解释器对应模块位置的搜索顺序
- 1.当前目录
- 2.所有在shell变量PYTHONPATH下的每个目录
- 3.Python会察看默认路径。UNIX下,默认路径⼀般为/usr/local/lib/python 模块搜索路径存储在system模块的sys.path变量量中。变量里包含当前⽬录,PYTHONPATH和由安装过 程决定的默认目录。
- 包:将有联系的模块文件组织在一起,放在同一个文件夹下,并在这个文件夹下创建一个名字为__init__.py的文件
- 包是比模块更高层的概念,模块一般是一个文件,包是一个目录,一个包中可以包含很多个模块
- 导入包的方式
# 1.import 包名.模块名 # 2. from 包名 import * (此方式必须在__init__.py定义__all__变量,控制允许导入的列表)
6. 案例实现:学员管理系统
-
目录结构
StudentManageSystem |--student.py |--manager.py |--main.py
-
代码实现
student.py
class Student(): def __init__(self, name, gender, tel): self.name = name self.gender = gender self.tel = tel def __str__(self): print(f'{self.name},{self.gender},{self.tel}')
manager.py
from student import * class Manager(): def __init__(self): self.student_list = [] def run(self): self.load_data() # load data while True: # show mainpage self.show_main_page() # choose number try: num = int(input('请输入您要选择的操作:')) except: print('输入错误') continue # add if num == 1: self.add_student() # del elif num == 2: self.del_student() # modify elif num == 3: self.modify_student() # select elif num == 4: self.select_student() # show all elif num == 5: self.show_student_list() # save elif num == 6: self.save_info() # break elif num == 7: break else: print('输入信息有误,请重新输入!') continue @staticmethod def show_main_page(): print('------欢迎来到学员管理系统:------') print('1.增加成员') print('2.删除成员') print('3.修改成员') print('4.查询成员') print('5.显示所有成员信息') print('6.保存信息') print('7.退出') print('------------------------------') def add_student(self): name = input('请输入姓名:') gender = input('请输入性别:') tel = input('请输入手机号:') s = Student(name, gender, tel) self.student_list.append(s) self.save_info() print('~~添加成功!~~') def del_student(self): name = input('请输入学生姓名:') for i in self.student_list: if i.name == name: self.student_list.remove(i) self.save_info() print('~~删除成功!~~') return print('~~未查询到此学员信息!~~') def modify_student(self): name = input('请输入学生姓名:') gender = input('请输入性别:') tel = input('请输入手机号:') for i in self.student_list: if i.name == name: i.gender = gender i.tel = tel self.save_info() print('~~修改成功!~~') return print('~~未查询到此学员信息!~~') def select_student(self): name = input('请输入学生姓名:') for i in self.student_list: if i.name == name: print(i.__dict__) return print('~~未查询到此学员信息!~~') def show_student_list(self): self.load_data() print('------------------------------') print('姓名\t性别\t电话\t') for i in self.student_list: print(f'{i.name}\t{i.gender}\t{i.tel}') print('------------------------------') def save_info(self): f = open('students.data', 'w', encoding='utf8') students = str([i.__dict__ for i in self.student_list]) f.write(students) f.close() print('保存成功!') def load_data(self): try: f = open('students.data', 'r', encoding='utf8') except: f = open('students.data', 'w', encoding='utf8') else: data = f.read() if data != '': # eval用来把字符串转换成相应的对象 new_list = eval(data) self.student_list = [Student(i.get('name',''), i.get('gender',''), i.get('tel','')) for i in new_list] finally: f.close()
main.py
from manager import * if __name__ == '__main__': m = Manager() m.run()