Python 基础入门学习
五.面向对象
-
类是对一系列具有相同特征和行为的事物的统称,是一个抽象的概念,不是真实存在的事物。对象是由类创建出来的真实存在的事物。
#创建类 class 类名(): #类名要满足标识符命名规则,同时遵循大驼峰命名习惯 代码 ...... def 函数名(self): #self指调用该函数的对象 代码 #创建对象 对象名 = 类名()
-
类外面添加对象属性:
对象名.属性名 = 值
类外面获取对象属性:
对象名.属性名
类里面获取对象属性:
self.属性名
综合实例:
class Washer(): def wash(self): print('wash the clothes!') def get_size(self): print(f'此洗衣机的尺寸是{self.width} X {self.height}') haier1 = Washer() haier1.width = 500 haier1.height = 300 haier2 = Washer() haier2.width = 600 haier2.height = 400 print(haier1.width) haier1.get_size() haier2.get_size()
-
魔法方法: __init__() 、 __str__()、__del__()。
#1. __init__() 初始化对象。 #创建对象时默认被调用;不需开发者传递self参数,python解释器会自动把当前对象引用传递过去。 class washer(): def __init__(self,width,height): self.width = width self.height = height def print_info(self): print(f'{self.width} X {self.height}') h = washer(500,800) h.print_info() #输出结果 500 X 800 #2. __str__() 使得用print输出对象时,输出该方法中return的数据,而不再输出对象的内存地址。 def __str__(self): return "这是洗衣机对象!" print(h) #输出结果 这是洗衣机对象! #3. __del__() 当删除对象时,python解释器会默认调用__del__()方法 def __del__(self): print(f'{self}对象已经被删除!') del h #输出结果 <__main__.washer object at 0x000002531DF744F0>对象已经被删除!
-
两个案例:
烤地瓜
#需求:1.被烤时间和地瓜状态相对应 2.用户可按意愿添加调料 class SweetPotato(): def __init__(self): self.cook_time=0 self.cook_state='生的' self.condiments=[] def cook(self, time): if time >=0: 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 = '糊了!' else: print('时间刺客?!') def add_condiment(self, con): self.condiments.append(con) def __str__(self): return f'这个地瓜烤了{self.cook_time}分钟,状态是{self.cook_state},添加的调料有{self.condiments}' p = SweetPotato() p.add_condiment('番茄酱') print(p) p.cook(8) p.add_condiment('芥末') print(p) # 这个地瓜烤了0分钟,状态是生的,添加的调料有['番茄酱'] # 这个地瓜烤了8分钟,状态是糊了!,添加的调料有['番茄酱', '芥末']
搬家具
#需求 将小于房子剩余面积的家具摆放到房子中 class Furniture(): def __init__(self,name,area): self.name = name self.area = area class House(): def __init__(self,adress,area): self.adress = adress self.area = area self.free_area = 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('家具太大,剩余面积不足,无法容纳') def __str__(self): return f'这个房子的地址是{self.adress},总面积是{self.area},当前剩余面积是{self.free_area},家具有{self.furniture}' bed = Furniture('双人床',6) sofa = Furniture('沙发',10) court = Furniture('高尔夫球场',1000) house = House('陆家嘴',200) print(house) house.add_furniture(bed) house.add_furniture(sofa) house.add_furniture(court) print(house) #这个房子的地址是陆家嘴,总面积是200,当前剩余面积是200,家具有[] #家具太大,剩余面积不足,无法容纳 #这个房子的地址是陆家嘴,总面积是200,当前剩余面积是184,家具有['双人床', '沙发']
-
继承: Python面向对象的继承指的是多个类之间的所属关系,即子类默认继承父类的所有属性和方法,具体如下:
#定义父类A class A(object): def __init__(self): self.num = 1 def infor_print(self): print(self.num) #定义子类B,继承父类A class B(A): pass #创建对象,验证对象继承 result = B() result.info_print()
在python中,所有类默认继承object类,object类是顶级类或基类;其他子类叫派生类。
拓展:python2中的经典类 和 python3中的新式类
#经典类(不由任意内置类型派生出的类) class 类名: 代码 ...... #新式类 class 类名(object): 代码 ...... #在今后的学习和运用中,统一使用新式类
单继承:一个子类继承一个父类,这种单一的继承关系称为单继承。
多继承:一个子类同时继承多个父类。
class 子类(父类A,父类B,父类C) #当两个父类中的属性和方法有同名时,优先继承第一个父类中的同名属性和方法,即继承A类。
子类重写父类同名属性与方法:在子类中可以重写与父类中同名的属性和方法。子类创建的对象调用属性和方法时,会调用子类中重写的属性和方法。
拓展: **__mro__**顺序 方法查看类的继承层级顺序。
print(类名.__mro__)
子类调用父类同名属性和方法:在子类中重写了父类中同名属性与方法的情况下,调用父类中的同名属性和方法。
class 子类B(父类A): def 同名方法(self): #如果之前调用了父类的属性和方法,则父类属性会覆盖子类属性,故在调用子类属性前,先调用子类自己的初始化 self.__init__(self) 代码 def 调用父类方法(self): #调用父类方法,为保证调用到的属性也是父类的属性,必须在调用方法前调用父类的初始化 父类A.__init__(self) 父类A.同名方法(self)
多层继承:一般指大于两层的继承关系。
class A(object): ... class B(A): ... class C(B): #多层继承 ...
super()调用父类方法:自动查找父类,直接调用父类的属性方法,调用顺序遵循__mro__类属性的顺序。
class A(object) class B(A) class C(B): #方法一:原始方法 def useAB(self): A.__init__(self) A.同名方法(self) B.__init__(self) b.同名方法(self) #方法二:super()方法 #方法2.1 super(当前类名,self).函数() def useAB(self): super(C,self).__init__() super(C,self).同名方法() #此时会调用父类B的方法;若想调用A类的方法,需要在B类的同名方法中添加同样的super方法代码来调用A类 #方法2.2 super().函数() def useAB(self): super().__init__(self) super().同名方法() #同样调用父类B的方法;无法直接调用父类的父类A的属性和方法
-
私有权限
设置私有属性和方法:在属性名和方法名前面加上两个下划线。
私有属性和私有方法只能在类内访问和修改,即子类无法继承或直接访问父类的私有属性和方法。
class A(object): def __init__(self): self.name = 'A' self.__money = 99999 #私有属性 def __CostMoney(self,money): #私有方法 self.__money -= money
获取和修改私有属性值:可在类内定义公有函数来获取和修改 私有属性值,在类外调用该函数来实现获取和修改私有属性功能。
#一般在类内用函数名get_xx来获取私有属性,用set_xx来修改私有属性 class A(object): def __init__(self): self.__money = 99999 def get_money(self): return self.__money def set_money(self,new_money): self.__money = new_money class B(A): pass b = B() b.get_money() #成功获取父类中的私有属性 b.set_money(0) #成功修改父类中的私有属性
-
多态:一种使用对象的方式,子类重写父类方法,调用不同子类对象的相同父类方法,可以产生不同的执行结果。即传入不同的对象,产生不同的结果。
-
类属性和实例属性:类属性即类所拥有的属性,它为该类所有对象共有。类属性可以用 类对象 或 实例对象 访问。
类属性只能通过类对象修改。
#修改类属性 类名.属性 = 值
-
类方法:需要用装饰器
@classmethod
来标识其为类方法,类方法第一个参数必须是类对象,一般以cls
作为第一个参数。class A(object): __num = 777 @classmethod def get_num(cls): return cls.__num obj = A() print(obj.get_num())
-
静态方法:通过装饰器
@staticmethod
进行修饰,静态方法即不需要传递类和对象的方法,有利于减少不必要的内存占用和性能消耗。class A(object): @staticmethod def info_print(): print('这是A类')
六.异常
-
异常的定义:解释器检测到错误时无法继续执行,并出现一些错误的提示,这就是所谓的异常。
异常的作用:使得解释器检测到错误时,转而执行另一句没错误的语句,使得程序不因一个错误而停止下来。
-
基本写法:
try: 可能发生错误的代码 except: 出现异常时执行的代码 else: 没有异常时执行的代码 finally: 无论是否异常都要执行的代码
体验案例:
#需求:尝试以r模式打开文件,若文件不存在(发生错误),则以w方式打开 try: f = open('test.txt','r') except: f = open('test.txt','w')
-
捕获指定异常:
try: print(num) except (NameError, ZeroDivisionError) as result: print(result) #捕获的异常描述信息 num = 777 print(num) #若尝试执行代码的异常类型和要捕获的异常类型不一致,则无法捕获异常 #一般try下方只放一行尝试执行的代码
-
捕获所有异常:利用 Exception 类
#Exception是所有程序异常类的父类 try: 可能错误的代码 except Exception as result: print(result)
-
异常中的 else 和 finally:
try: f = open('test.txt','r') except Exception as result: f = open('test.txt','w') print(result) else: # try 下方的代码无异常时执行的代码 print('代码没有异常和错误') finally: #无论有无异常都要执行的代码,如关闭文件 f.close()
-
异常的传递:
import time try: f = open('test.txt') #默认打开模式为只读 #尝试循环读取内容 try: while True: con = f.readline() #无内容时退出循环 if len(con) == 0: break time.sleep(2) print(con) except: #在命令提示符中按下 Ctrl+C 终止程序 print('程序被意外终止') except: print('文件不存在')
-
自定义异常: 抛出自定义异常的语法为
raise 异常类对象
#自定义异常类,继承Exception class ShortInputError(Exception): def __init__(self,length,min_length): self.length=length self.min_length=min_length #设置抛出异常的描述信息 def __str__(self): return f'输入长度为{self.length},不能少于{self.min_length}个字符' def main(): #封装代码 try: con = input('请输入密码: ') if len(con) < 6: raise ShortInputError(len(con),6) except Exception as result: print(result) else: print('密码输入完成') main()
七.模块
-
了解模块:Python模块(Module),是一个Python文件,包含了Python对象定义和语句。
-
导入和调用模块:
#导入及调用模块 #写法一 import 模块名 #导入模块中的所有代码 模块名.功能名() #写法二 from 模块名 import 功能1,功能2... #单个调用某功能 功能名() #即不需要在功能前写 "模块名." #写法三 from 模块名 import * 功能名() #一般用第一种写法
利用as定义别名:定义别名后,使用时要用定义的别名
#模块定义别名 import 模块名 as 别名 #功能定义别名 from 模块名 import 功能 as 别名
-
制作模块:模块名字就是py文件的名字。自定义模块名必须要符合标识符命名规则。
#只会在当前文件中调用下列测试代码,其他导入的文件内不符合该条件,也就不会执行测试代码 # __name__ 是系统变量,是模块的标识符。如果在自身模块里,则其值为 '__main__';否则是所在模块的名字 if __name__ == '__main__': 测试模块功能代码
-
模块定位顺序:当导入一个模块,Python解释器对模块位置的搜索顺序是:
当前目录 > 搜索在shell变量PYTHONPATH下的每个目录 > 操作系统的默认python路径
注意:
自己的文件名不要和已有模块名重复,否则模块功能无法使用。
使用
from 模块名 import 功能
时,若功能名字重复,则调用最后定义的或最后导入的功能。当使用
import 模块名
的写法调用模块时,不需要担心功能名重复。 -
__all__
列表:如果一个模块文件中有__all__
变量列表,当使用from 模块名 import *
导入该模块时,则只能导入__all__
列表中的元素。 -
包:包将有联系的模块组织在一起,放到同一个文件夹下,并且在这个文件夹内自动生成一个名字为
__init__.py
的文件,这个文件控制着包的导入行为。创建包:在Pycharm中 New -> Python Package -> 输入包名 - > [OK] 即可新建一个包。
导入包:
#方法一 import 包名.模块名 包名.模块名.功能 #方法二 #注意,必须在 __init__.py 文件中添加 __all__ = [] 来控制允许导入的模块列表 from 包名 import * 模块名.功能
面向对象综合实例
#使用面向对象编程思想完成学员管理系统的开发
#为了方便维护代码,一般一个角色一个程序文件
#项目要有主程序入口,习惯为main.py
#系统要求:学员数据存储在文件中
#系统功能:添加学员、删除学员、修改学员信息、查询学员信息、显示所有学员信息、保存学员信息、退出系统等功能
#student.py
#学员类
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}'
#mangerSystem.py
#存储数据的: student.data
#存储数据的形式: 列表存储学员对象
#系统功能: 添加、删除、修改、查询、显示、保存学员信息
#管理系统类
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_menu()
elif menu_num == 6:
# 保存学员信息
self.save_student()
elif menu_num == 7:
# 退出系统 - 退出循环
break
#二. 系统功能函数
#2.1 显示功能菜单 -- 静态方法
@staticmethod
def show_menu():
print('请选择如下功能: ')
print('1.添加学员')
print('2.删除学员')
print('3.修改学员信息')
print('4.查询学员信息')
print('5.显示所有学员信息')
print('6.保存学员信息')
print('7.退出系统')
#2.2 添加学员
def add_student(self):
#1. 用户输入
name = input('请输入姓名: ')
gender = input('请输入性别: ')
tel = input('请输入手机号: ')
#2. 创建学员对象 -- 先导入student.py模块
student = Student(name,gender,tel)
#3. 将对象添加到学员列表
self.student_list.append(student)
#2.3 删除学员
def del_student(self):
#1. 用户输入目标学员姓名
del_name = input('请输入要删除的学员姓名:')
#2. 如果用户输入的目标学员存在则删除,否则提示不存在
for i in self.student_list:
if i.name == del_name:
self.student_list.remove(i)
break
else:
print('查无此人!')
#2.4 修改学员信息
def modify_student(self):
#1. 用户输入目标学员姓名
modify_name = input('请输入要修改的学员姓名: ')
#2. 如果用户输入的目标学员存在,则修改信息,否则提示不存在
for i in self.student_list:
if i.name == modify_name:
i.name = input('请输入学员姓名: ')
i.gender = input('请输入学员性别: ')
i.tel = input('请输入学员手机号: ')
print('修改成功!')
break
else:
print('查无此人!')
#2.5 查询学员信息
def search_student(self):
#1. 用户输入目标学员姓名
search_name = input('请输入要查询的学员姓名: ')
#2. 若存在,打印学员信息,否则提示不存在
for i in self.student_list:
if i.name == search_name:
print(f'姓名{i.name},性别{i.gender},手机号{i.tel}')
break
else:
print('查无此人!')
#2.6 显示所有学员信息
def show_student(self):
print('姓名\t性别\t手机号')
for i in self.student_list:
print(f'{i.name}\t{i.gender}\t{i.tel}')
#2.7 保存学员信息
def save_student(self):
# 拓展 __dict__方法,以字典方式返回类和对象内的属性
#1. 打开文件
f = open('student.data','w')
#2. 文件写入学员数据 - 先将学员对象数据转换成列表字典数据再做存储
new_list = [i.__dict__ for i in self.student_list]
# 文件内数据要求为字符串类型,故要先转换数据类型为字符串才能写入文件
f.write(str(new_list))
#3. 关闭文件
f.close()
#2.8 加载学员信息
def load_student(self):
#尝试以"r"模式打开数据文件,有异常则用"w"模式打开;存在则读取数据
try:
f = open('student.data','r')
except:
f = open('student.data','w')
else:
#1. 读取数据
data = f.read()
#2. 先将文件中的 字符串型字典数据 转换为 对象数据 后再存储到学员列表
new_list = eval(data)
self.student_list = [Student(i['name'],i['gender'],i['tel']) for i in new_list]
finally:
#3. 关闭文件
f.close()
#main.py
#导入模块
#from managerSystem import *
#启动管理系统
#if __name__ == '__main__':
student_manager = StudentManager()
student_manager.run()