Python面向对象总结-下篇

Posted by 新宇 on December 29, 2019

面向对象三大特性:封装、继承、多态

1. 多态

  1. 概念:在面向对象的编程思想中,一个类可以创建多个对象,每个对象和属性的行为之间会存在一些差异,编程过程中使用不同的对象,那么有可能得到不同的结果
  2. 优点:提高代码灵活性

     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. 类属性和实例属性

  1. 类属性
    • 类拥有的属性,被该类的所有实例共有;
    • 类属性可以使用类对象和实例对象访问;
    • 类属性只能通过类对象修改,不能通过实例修改
    • 如果通过实例对象修改类属性,表示创建了一个同名实例属性
    • 优点:始终保持一致,并只占用一分内存,更加节省内存空间;
     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. 类方法和静态方法

  1. 类方法: 通过@classmethod装饰器进行装饰的方法,传入的是类对象
    • 操作类属性/私有类属性方式时才使用
    • 类对象和实例对象都可以使用
  2. 静态方法:通过@staticmethod装饰器进行装饰的方法
    • 形参没有cls/self, 不需要传递类对象和实例对象
    • 减少不必要的内存消耗
  3. 类方法 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. 异常

  1. 概念:在程序运行过程中报的错误
  2. 异常会影响程序后续代码的运行
  3. try except 捕获的错误,可以用as为它起别名
  4. try except 只能捕获runtime产生的异常

     # 捕获异常的完整语句
     try:
         print(num)
     except (NameError, ZeroDivisionError) as e:
         print(e)
     else:
         print('try未产生异常时,会执行到')
     finally:
         print('不管是否出现异常,都会执行到')
    
  5. 自定义异常要继承自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('密码设置完成!')
    
  6. 常见的异常类型:
    • IOError:读写异常,主要是指要打开的文件不存在的错误提示
    • AttributeError:属性异常,特性引用和赋值失败时会引发属性错误
    • ImportError:导入了不存在的模块或功能
    • IndentationError:缩进错误
    • IndexError:索引错误,访问了不存在的数组索引
    • KeyError:访问了字典中不存在的key
    • SyntaxError:使用了错误的语法
    • NameError:试图访问的变量名不存在

5. 模块和包

  1. 模块就是python文件,以.py结尾,包含python对象和语句,定义了函数,类和变量,模块里也包含可执行代码;
  2. 模块导入的三种方式:

     import 模块名
    
     from 模块名 import 功能名
    
     from 模块名 import *
    
     # 为什么使用别名?
     # 1. 模块名太长
     # 2. 与自己定义的模块同名时,避免冲突和混淆
    
     # 定义别名后,只能使用别名
    
     import 模块名 as 别名
    
     from 模块名 import 功能名 as 别名
    
    
  3. python 常用的标准库: random,time,math,datetime,matplotlib,numpy,pandas,sys,os,requests,threading

  4. 制作模块
    • __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)
    
    
  5. Python解释器对应模块位置的搜索顺序
    • 1.当前目录
    • 2.所有在shell变量PYTHONPATH下的每个目录
    • 3.Python会察看默认路径。UNIX下,默认路径⼀般为/usr/local/lib/python 模块搜索路径存储在system模块的sys.path变量量中。变量里包含当前⽬录,PYTHONPATH和由安装过 程决定的默认目录。
  6. 包:将有联系的模块文件组织在一起,放在同一个文件夹下,并在这个文件夹下创建一个名字为__init__.py的文件
    • 包是比模块更高层的概念,模块一般是一个文件,包是一个目录,一个包中可以包含很多个模块
    • 导入包的方式
     # 1.import 包名.模块名
    
     # 2. from 包名 import * (此方式必须在__init__.py定义__all__变量,控制允许导入的列表)
    
    

6. 案例实现:学员管理系统

  1. 目录结构

     StudentManageSystem
     |--student.py
     |--manager.py
     |--main.py
    
  2. 代码实现

    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()