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