一、字符串、列表、元组、字典、集合
(一)字符串
1 .字符串的介绍
字符串不可变
2 .字符串输入输出
3.字符串的下标和切片
字符串切片格式:字符串变量[start:end]左闭右开 字符串变量[start:end:step]默认是从左向右一个一个取元素 step: 1.步长 2.方向 step正数--从左向右,step负数--从右向左
4.字符串的常见操作
(1)获取长度--len
(2)查找内容--find、index、rfind、rindex
find:从左向右查找,只要找到一个符合要求的则返回位置,如果没有找到任何符合要求的则返回-1 rfind:从右向左查找,只要找到一个符合要求的则返回位置,如果没有找到任何符合要求的则返回-1
index与find区别:index也是表示查找,如果找不到会报错
(3)判读--startswitch、endswitch、isalpha、isdigit、isalnum、isspase、isupper
startswitch:判断字符串是否以XX开头
endswitch:判断字符串是否以XX结尾
isalpha:判断是否是纯字母组成
isdigit:判断是否是纯数字组成
isalnum:判断是否是字母、数字组成
isspace:判断是否全部由空格组成
isupper:判断是否全部是大写字母组成的
islower:判断是否全部是小写字母组成的
(4)计算出现次数--count
count:统计指定字符的个数
(5)替换内容--replace
replace(old,new,count) count--没传值时,默认全部替换
(6)切割字符串--split、rsplit、splitlines、partition、rpartition
split('分割符',maxsplit)—返回结果是一个列表,maxsplit最多分割次数
rsplit('分割符')—从右向左分割
splitlines--按行分割
(7)修改大小写--capitalize、title、upper、lower
title--首字母大写
capitalize—把一句话中每个单词的第一个字母大写
(8)空格处理--ljust、rjust、center、lstrip、rstrip、strip
strip--去除左右空格
lstrip--去除左边空格
rstrip--去除右边空格
centet -- 添加空格,控制字符串的对齐方式为居中
ljust -- 添加空格,控制字符串的对齐方式为左对齐
rjust -- 添加空格,控制字符串的对齐方式为右对齐
(9)字符串拼接--join
注意:在Python中,字符串是不可变的!所有的字符串相关方法,都不会 改变原有字符串,都是返回一个结果,再这个新的返回值里,保留了执行后的结果!
5.格式化字符串
(二)列表
1.列表的声明
定义列表的格式:[元素1,元素2,元素3,...,元素n]
如何定义一个列表?
空列表:[]
有内容的列表:['A','B'],[[],[],[]]
列表中的元素可以是不同类型的
2.列表的增删改查
(1)添加元素
append()---追加元素
extend()---合并两个列表
insert(下标,元素)---在指定位置添加元素
两个列表整合为一个列表
list1 = ['火腿肠']
list2 = ['面包']list1 += list2 或 list1.extend(list2)
print(list1) //['火腿肠', '面包']
(2)删除元素
pop(index)---根据下标删除列表中的元素。下标不能超出范围,如果下标超出则会报错
pop()---如果不填下标,会从后往前依次删除
remove(element)---根据元素名称删除,只删除第一个元素,如果元素不存在的时候则会报错
del(index)---根据下标删除元素
clear()---清空列表
del 列表---删除列表,删除列表的指针指向
list3 = ['火腿肠','酸奶','酸奶','辣条','面包','薯条','酸奶']
for i in list3:
if i == '酸奶':
list3.remove(i)
print(list3) //['火腿肠', '辣条', '面包', '薯条', '酸奶']为什么会出现漏删的情况?
(3)修改元素
根据下标修改
insert(位置,元素)---元素占了位置,其他元素只能向后移动
(4)查找元素
元素 in 列表---返回bool类型
元素 not in 列表---元素不在列表中返回true
列表.index(元素)---返回该元素的下标,如果没有则报错
列表.count(元素)---返回整数
(5)列表的排序
sort()---默认升序,可以通过reverse参数来控制升序还是降序
sort(reverse=True)---降序排列
reverse()---对原有列表进行反转
3.遍历列表
(1)while循环遍历
(2)for循环遍历
元素交换
a,b = b,a
4.列表嵌套
5.深拷贝浅拷贝
拷贝:数据一分二的复制过程,防止数据被意外破话。
深拷贝:复制整个依懒的变量。占用内存较少,修改深层数据会被破坏
浅拷贝:复制过程中,只复制一层变量,不会复制深层变量绑定的对象的复制过程。占用内存较多
import copy
list01 = ['北京',['上海','深圳']]
#赋值:传递列表的地址,列表只有一份
list02 = list01
#浅拷贝--第一层两份,深层两份
list03 = list01[:]
#深拷贝--所有层2份
list04 = copy.deepcopy(list01)
list04[0] = '北京04'
list04[1][1] = '深圳04'
6.列表与字符串相互转换
(1)列表转字符串
result = "连接符".join(列表)
#在终端中,循环录入字符串,如果录入为空则停止循环
list = []
while True:
n = input("请输入:")
if n != '':
list.append(n)
else:
break
result = '_'.join(list)
print(result)
(2)字符串转列表
列表 = “a-b-c-d”.split(“分隔符”)
'''
练习:将下列英文语句按照单词进行翻转.
转换前:To have a government that is of people by people for people
转换后:people for people by people of is that government a have To
'''
str = 'To have a government that is of people by people for people'
list = str.split(' ')
print(list)
list.reverse()
str1 = ' '.join(list)
print(str1)
7.列表推导式
(1)概念
使用简易的方法,将可迭代对象转换成列表
(2)语法
变量 = [表达式 for 变量 in 可迭代对象]
变量 = [表达式 for 变量 in 可迭代对象 if条件]
(3)说明
如果条件不满足,则可迭代对象的元素将被丢弃
''''
练习,生成10-30之间能被3或者5整除的数字
'''
list = [item for item in range(10,31) if item%3==0 or item%5==0]
print(list)
(三)元组
Python的元组与列表类似,不同之处在于元组的元素不能修改(增、删、改),元组使用小括号,列表使用方括号
列表内存机制:预留空间+自动扩容
元组内存机制:按需分配
Python有哪些数据类型?
可变数据类型和不可变数据类型
可变类型:预留空间+按需分配
不可变类型:按需分配
可变数据类型优点:适应需求变化
可变数据类型缺点:占用空间较大
不可变数据类型优点:占用空间较小
不可变数据类型缺点:操作不方便
1.元组的声明
(1)创建空元组
元组名 = ()
元组名 = tuple()
(2)创建非空元组
元组名 = (10,)
元组名 = (10,20,30)
元组名 = 100,200,300
元组名 = tuple(可迭代对象)
注意:如果元组中只有一个元素,必须加逗号
拆包: 多个变量 = 容器
t = (10,20)
a,b = t
print(a) # 10
print(b) # 20
#元组地址练习
name = '张无忌'
names = ['赵敏','周芷若']
tuple01 = ('张翠山',name,names)
name = '无忌哥哥'
tuple01[2][0] = '敏儿'
print(tuple01) #('张翠山', '张无忌', ['敏儿', '周芷若'])
2.获取元素
变量 = 元组名[索引]
变量 = 元组名[切片] # 赋值给变量的是切片所创建的新列表
3.遍历元组
(1)正向遍历
for 变量名 in 元组名:
变量名就是元素
(2)反向遍历
for 索引名 in range(len(列表名)-1,-1,-1):
元组名[索引名]就是元素
4.作用
(1) 元组与列表都可以存储一系列变量,由于列表会预留内存空间,所以可以增加元素。
(2) 元组会按需分配内存,所以如果变量数量固定,建议使用元组,因为占用空间更小。
(3) 应用:
变量交换的本质就是创建元组:x, y = (y, x )
格式化字符串的本质就是创建元组:"姓名:%s, 年龄:%d" % ("tarena", 15)
(四)字典
1.定义
(1)由一系列键值对组成的可变散列容器
(2)散列:对键进行哈希运算,确定在内存中的存储位置,每条数据存储后无先后顺序
(3)键必须唯一且不可变(字符串/数字/元组),值没有限制
2.字典的操作
(1)字典的创建
字典名 = {键1:值1,键2:值2}
字典名 = dict (可迭代对象)
dict = {
'name':'刘慧杰',
'age': 25,
'sex': '女'
}
(2)添加元素
语法:字典名[键] = 数据
说明: 键不存在,创建变量。键存在,修改值
(3)获取元素
变量 = 字典名[键] # 没有键则错误
(4)遍历字典
dict = {
'name':'刘慧杰',
'age': 25,
'sex': '女'
}
for key in dict:
print(dict[key])
for value in dict.values():
print(value)
for item in dict.items():
print(item)
for key,value in dict.items():
print(key,value)
(5)删除元素
del 字典名['键']
3.字典转换成列表
dict = {
'name':'刘慧杰',
'age': 25,
'sex': '女'
}
print(list(dict)) #['name', 'age', 'sex']
print(list(dict.values())) #['刘慧杰', 25, '女']
print(list(dict.items())) #[('name', '刘慧杰'), ('age', 25), ('sex', '女')]
4. 字典推导式
(1) 定义
使用简易方法,将可迭代对象转换为字典。
(2) 语法
{键:值 for 变量 in 可迭代对象}
{键:值 for 变量 in 可迭代对象 if 条件}
'''
将两个列表,合并为一个字典
姓名列表["张无忌","赵敏","周芷若"]
房间列表[101,102,103]
{101: '张无忌', 102: '赵敏', 103: '周芷若'}
'''
name = ["张无忌","赵敏","周芷若"]
room = [101,102,103]
dict = {}
'''for i in range(len(name)):
key = name[i]
value = room[i]
dict[key] = value
print(dict)'''
dict = {name[i]:room[i] for i in range(len(name)) }
print(dict)
'''
练习2:
颠倒练习1字典键值
{'张无忌': 101, '赵敏': 102, '周芷若': 103}
'''
new_dict = {v:k for k,v in dict.items()}
print(new_dict)
(五)Python格式化
1.字符串插值
使用字符串插值,您可以将变量嵌入到字符串中。
name = "Alice"
age = 30
print(f"My name is {name} and I'm {age} years old.")
在Python 3.5及以下版本中,您可以使用.format()方法执行字符串插值
name = "Alice"
age = 30
print("My name is {} and I'm {} years old.".format(name, age))
2.百分号格式化
name = "Alice"
age = 30
print("My name is %s and I'm %d years old." % (name, age))
3.模板字符串格式化
4.字符串拼接
name = "Alice"
age = 30
print("My name is " + name + " and I'm " + str(age) + " years old.")
二、函数
1.pycharm快捷键
Ctrl + P 参数信息(在方法中调用参数)
Ctrl + Q 快速查看文档
2.定义
(1) 用于封装一个特定的功能,表示一个功能或者行为。
(2) 函数是可以重复执行的语句块, 可以重复调用。
3.作用
提高代码的可重用性和可维护性(代码层次结构更清晰)。
4.基础语法
4.1定义函数
(1) 语法
def 函数名(形式参数):
函数体
(2) 说明
def 关键字:全称是define,意为”定义”。
函数名:对函数体中语句的描述,规则与变量名相同。
形式参数:函数定义者要求调用者提供的信息。
函数体:完成该功能的语句。
(3) 函数的第一行语句建议使用文档字符串描述函数的功能与参数。
4.2调用函数
(1) 语法
函数名(实际参数)
(2) 说明
根据形参传递内容。
4.3函数返回值
(1) 定义
函数定义者告诉调用者的结果。
(2) 语法
return 数据
(3) 说明
return后没有语句,相当于返回 None。
函数体没有return,相当于返回None。
5.函数内存分布
#1.将函数代码加入到内存代码区
def func01(p1,p2):
data = p1+p2
return data
num01 = 10
#2.调用函数时会在内存中开辟一块空间
#存储函数内部创建的变量
res = func01(num01,20)
#3.函数执行后,改空间立即释放
print(res)
6.可变/不可变类型在传参时的区别
(1) 不可变类型参数有:
数值型(整数,浮点数)
布尔值bool
None 空值
字符串str
元组tuple
(2) 可变类型参数有:
列表 list
字典 dict
(3) 传参说明:
不可变类型的数据传参时,函数内部不会改变原数据的值。
可变类型的数据传参时,函数内部可以改变原数据。
7.函数参数
7.1 实参传递方式argument
7.1.1 位置实参
定义:实参与形参的位置依次对应。
def fun01(p1, p2, p3):
print(p1)
print(p2)
print(p3)
# 位置实参:根据顺序与形参进行对应
fun01(1, 2, 3)
7.1.2 序列实参
定义:实参用*将序列拆解后与形参的位置依次对应。
一序列拆分为多参数,按照顺序对应
def func01(p1, p2, p3):
print(p1, p2, p3)
# 序列实参:拆,按照顺序与形参对应
list01 = [1, 2, 3]
name = "孙悟空"
tuple01 = (4, 5, 6)
# func01(list01)
func01(*list01) # 拆 1, 2, 3
func01(*name) # 拆 孙 悟 空
func01(*tuple01) # 拆 4, 5, 6
7.1.3 关键字实参
定义:实参根据形参的名字进行对应。
def fun01(p1, p2, p3):
print(p1)
print(p2)
print(p3)
# 关键字实参:根据名字与形参进行对应
fun01(p1=1, p2=2, p3=3)
fun01(p2=2, p1=1, p3=3)
7.1.4 字典关键字实参
(1) 定义:实参用**将字典拆解后与形参的名字进行对应。
(2) 作用:配合形参的缺省参数,可以使调用者随意传参。
一字典拆分为多参数,按照名称对应,键名必须和形参名一致
def func01(p1, p2, p3):
print(p1, p2, p3)
# 字典实参:拆,按照名称与形参对应
dict01 = {"p2":"B","p1":"A","p3":"C"}
func01(**dict01) #p1,p2,p3
7.2形参定义方式parameter
7.2.1 默认形参
(1) 语法:
def 函数名(形参名1=默认值1, 形参名2=默认值2, ...):
函数体
(2) 说明:
默认参数必须自右至左依次存在,如果一个参数有默认值,则其右侧的所有参数都必须有默认值。
def func01(p1 =0, p2="", p3=100):
print(p1)
print(p2)
print(p3)
func01(p2=2)
func01(p2=2,p3=3)
# 支持同时使用位置实参与关键字实参
func01(1,p3=3)
# 注意1:先位置实参,后关键字实参
# func01(p1 =1,2,3) # 错误
7.2.2 位置形参
语法:
def 函数名(形参名1, 形参名2, ...):
函数体
7.2.3 命名关键字形参
(1) 语法:
def 函数名(*args, 命名关键字形参1, 命名关键字形参2, ...): 函数体
def 函数名(*, 命名关键字形参1, 命名关键字形参2, ...):
函数体
(2) 作用:
强制实参使用关键字传参
# 命名关键字形参:
# 星号元组形参后面的位置形参
# 限制实参必须是关键字实参
def func01(*args, p1, p2):
print(args)
print(p1)
print(p2)
func01(p1=1, p2=2)
func01(1, 2, 3, p1=1, p2=2)
def func02(p1, *, p2=0):
print(p1)
print(p2)
# 通常星号后面的命名关键字形参属于辅助参数,可选.
func02(1)
func02(1, p2=2)
7.2.4 星号元组形参
(1) 语法:
def 函数名(*元组形参名):
函数体
(2) 作用:
可以将多个位置实参合并为一个元组
(3) 说明:
一般命名为'args'
形参列表中最多只能有一个
# 位置实参数量可以无限
def func01(*args):
print(args)
func01() # 空元组
func01(1, 2, 34) # (1, 2, 34)
# 不支持关键字实参
# func01(args = 1,a=1)
7.2.5 双星号字典形参
(1) 语法:
def 函数名(**字典形参名):
函数体
(2) 作用:
可以将多个关键字实参合并为一个字典
(3) 说明:
一般命名为'kwargs'
形参列表中最多只能有一个
# 关键字实参数量无限
def func01(**kwargs):
print(kwargs) # {'a': 1, 'b': 2}
func01(a=1,b=2)
# func01(1,2,3) # 报错
7.2.6 形参自左至右的顺序
位置形参 --> 星号元组形参 --> 命名关键字形参 --> 双星号字典形参
def fun01(list_target):
print(list_target)
def fun02(*args):
print(args)
def fun03(*args,**kwargs):
print(args)
print(kwargs)
def fun04(p1,p2,*,p4,**kwargs):
print(p1)
print(p2)
print(p4)
print(kwargs)
fun01([1,2,3])
fun02(1,2,3)
fun02(*[1,2,3])
fun03(1,2,3,a=4,b=5)
fun04(10,20,p4=30,a=4,b=5)
三、面向对象
1.概述
1.1 面向过程
(1) 定义:分析出解决问题的步骤,然后逐步实现。
例如:婚礼筹办
-- 请柬(选照片、措词、制作)
-- 宴席(场地、找厨师、准备桌椅餐具、计划菜品、购买食材)
-- 仪式(定婚礼仪式流程、请主持人)
(2) 公式:程序 = 算法 + 数据结构
(3) 优点:所有环节、细节自己掌控。
(4) 缺点:考虑所有细节,工作量大。
1.2 面向对象
(1) 定义:找出解决问题的人,然后分配职责。
例如:婚礼筹办
-- 发请柬:找摄影公司(拍照片、制作请柬)
-- 宴席:找酒店(告诉对方标准、数量、挑选菜品)
-- 婚礼仪式:找婚庆公司(对方提供司仪、制定流程、提供设备、帮助执行)
(2) 公式:程序 = 对象 + 交互
(3) 优点
a. 思想层面:
-- 可模拟现实情景,更接近于人类思维。
-- 有利于梳理归纳、分析解决问题。
b. 技术层面:
-- 高复用:对重复的代码进行封装,提高开发效率。
-- 高扩展:增加新的功能,不修改以前的代码。
-- 高维护:代码可读性好,逻辑清晰,结构规整。
(4) 缺点:学习曲线陡峭。
2. 类和对象
(1) 抽象:从具体事物中抽离出共性、本质,舍弃个别、非本质过程。
(2) 类:一个抽象的概念,即生活中的”类别”。
(2) 对象:类的具体实例,即归属于某个类别的”个体”。
(3) 类是创建对象的”模板”。
2.1 语法
2.1.1 定义类
(1) 代码
class 类名:
"""
文档说明
"""
def __init__(self,参数):
self.实例变量 = 参数
def 实例方法(self,参数):
pass
(2) 说明
-- 类名所有单词首字母大写.
-- init 也叫构造函数,创建对象时被调用,也可以省略。
-- self 变量绑定的是被创建的对象,名称可以随意。
2.1.2 实例化对象
(1) 代码
对象名 = 类名(数据)
(2) 说明
-- 对象名存储的是实例化后的对象地址
-- 类名后面的参数按照构造函数的形参传递
2.2 实例成员
实例就是对象(具体化)
成员包括变量和方法
2.2.1 实例变量
(1) 语法
a. 定义:对象.变量名
b. 调用:对象.变量名
(2) 说明
a. 首次通过对象赋值为创建,再次赋值为修改.
b. 通常在构造函数(__init_)中创建实例变量
(3) 每个对象存储一份,通过对象地址访问
(4) 作用:描述某个对象的数据。
(5) __dict__:对象的属性,用于存储自身实例变量的字典。
class Person:
#数据成员
def __init__(self, height, name=None, sex='男'):
self.height = height
self.name = name
self.sex = sex
#方法成员
def work(self):
print(self.name)
class Phone:
def __init__(self, brand=None, price=None, color=None):
self.brand = brand
self.price = price
self.color = color
def tonghua(self):
print('手机可以通话')
xiaomi = Phone('小米',2000,'白色')
xiaomi.tonghua()
print(xiaomi.__dict__)
2.2.2 实例方法
(1) 定义
def 方法名称(self, 参数):
方法体
(2) 调用:
对象.方法名称(参数)
# 不建议通过类名访问实例方法
(3) 说明
-- 至少有一个形参,第一个参数绑定调用这个方法的对象,一般命名为self。
-- 无论创建多少对象,方法只有一份,并且被所有对象共享。
(4) 作用:表示对象行为。
class Epidemic:
def __init__(self, region="", new=0, now=0, total=0):
self.region = region
self.new = new
self.now = now
self.total = total
# 疫情信息
list_epidemic = [
Epidemic("台湾",16,2339,16931),
Epidemic("陕西",182,859,1573),
Epidemic("浙江",2,505,2008),
]
def print_all_epidemic():
''' --打印所有疫情信息,'''
for epidemic in list_epidemic:
print(f"{epidemic.region}新增{epidemic.new},现有{epidemic.now},总计{epidemic.total}")
def find_region_by_new_gt_value():
''' --查找新增人数大于10的地区名称(将结果存入新列表)'''
new_list = []
for epidemic in list_epidemic:
if epidemic.new > 10:
new_list.append(epidemic)
return new_list
def get_max_epidemic_by_now():
'''# --查找现有人数最大的地区信息(结果为字典)'''
max = list_epidemic[0]
for i in range(1,len(list_epidemic)):
if list_epidemic[i].now > max.now:
max = list_epidemic[i]
return max
def descending_order_by_now():
'''--根据现有人数对疫情信息降序(大->小)排列'''
for r in range(len(list_epidemic) - 1):
for c in range(r + 1, len(list_epidemic)):
if list_epidemic[r].new < list_epidemic[c].new:
list_epidemic[r], list_epidemic[c] = list_epidemic[c], list_epidemic[r]
print_all_epidemic()
re2 = find_region_by_new_gt_value()
for item in re2:
print(item.__dict__)
re1 = get_max_epidemic_by_now()
print(re1.__dict__)
descending_order_by_now()
for item in list_epidemic:
print(item.__dict__)
print(list_epidemic)
2.2.3 跨类调用
方法一:直接创建对象
# 写法1:直接创建对象
# 语义:老张每次创建一辆新车去
class Person:
def __init__(self, name=""):
self.name = name
def go_to(self,position):
print("去",position)
car = Car()
car.run()
class Car:
def run(self):
print("跑喽~")
lz = Person("老张")
lz.go_to("东北")
方法二:在构造函数中创建对象
# 写法1:直接创建对象
# 语义:老张每次创建一辆新车去
class Person:
def __init__(self, name=""):
self.name = name
def go_to(self,position):
print("去",position)
car = Car()
car.run()
class Car:
def run(self):
print("跑喽~")
lz = Person("老张")
lz.go_to("东北")
方法三:通过参数传递
# 方式3:通过参数传递
# 语义:老张用交通工具去
class Person:
def __init__(self, name=""):
self.name = name
def go_to(self,vehicle,position):
print("去",position)
vehicle.run()
class Car:
def run(self):
print("跑喽~")
lz = Person("老张")
benz = Car()
lz.go_to(benz,"东北")
3、三大特征
3.1 封装性
3.1.1.数据角度
(1)定义:将一些基本数据类型复合成一个自定义类型
(2)优势
-- 将数据与对数据的操作相互关联
-- 代码可读性更高(类是对象的模板)。
3.1.2 行为角度
(1) 定义:
向类外提供必要的功能,隐藏实现的细节。
(2) 优势:
简化编程,使用者不必了解具体的实现细节,只需要调用对外提供的功能。
- 作用:无需向类外提供的成员,可以通过私有化进行屏蔽。
(3) 私有成员:
-- 做法:命名使用双下划线开头。
-- 本质:障眼法,实际也可以访问。
私有成员的名称被修改为:类名__成员名,可以通过__dict__属性查看。
class MyClass:
def __init__(self, data):
self.__data = data
def __func01(self):
print("func01执行了")
m01 = MyClass(10)
# print(m01.__data) # 无法访问
print(m01._MyClass__data)
print(m01.__dict__) # {'_MyClass__data': 10}
# m01.__func01() # 无法访问
m01._MyClass__func01()
3.2 继承
3.2.1 继承方法
(1) 语法:
class 父类:
def 父类方法(self):
方法体
class 子类(父类):
def 子类方法(self):
方法体
儿子 = 子类()
儿子.子类方法()
儿子.父类方法()
(2) 说明:
子类直接拥有父类的方法.
3.2.2 内置函数
(1) isinstance(对象, 类型)
返回指定对象是否是某个类的对象。
(2) issubclass(类型,类型)
返回指定类型是否属于某个类型。
(3) 演示
# 对象 是一种 类型: isinstance(对象,类型)
# 老师对象 是一种 老师类型
print(isinstance(qtx, Teacher)) # True
# 老师对象 是一种 人类型
print(isinstance(qtx, Person)) # True
# 老师对象 是一种 学生类型
print(isinstance(qtx, Student)) # False
# 人对象 是一种 学生类型
print(isinstance(p, Student)) # False
# 类型 是一种 类型: issubclass(类型,类型)
# 老师类型 是一种 老师类型
print(issubclass(Teacher, Teacher)) # True
# 老师类型 是一种 人类型
print(issubclass(Teacher, Person)) # True
# 老师类型 是一种 学生类型
print(issubclass(Teacher, Student)) # False
# 人类型 是一种 学生类型
print(issubclass(Person, Student)) # False
# 是的关系
# 老师对象的类型 是 老师类型
print(type(qtx) == Teacher) # True
# 老师对象的类型 是 人类型
print(type(qtx) == Person) # False
3.2.3 继承数据
(1) 语法
class 子类(父类):
def __init__(self,父类参数,子类参数):
super().__init__(参数) # 调用父类构造函数
self.实例变量 = 参数
(2) 说明
子类如果没有构造函数,将自动执行父类的,但如果有构造函数将覆盖父类的。此时必须通过super()函数调用父类的构造函数,以确保父类实例变量被正常创建。
3.2.4 定义
(1) 概念: 重用现有类的功能,并在此基础上进行扩展。
(2) 说明:子类直接具有父类的成员(共性),还可以扩展新功能。
(3) 相关知识
-- 父类(基类、超类)、子类(派生类)。
-- 父类相对于子类更抽象,范围更宽泛;子类相对于父类更具体,范围更狭小。
-- 单继承:父类只有一个(例如 Java,C#)。
-- 多继承:父类有多个(例如C++,Python)。
-- Object类:任何类都直接或间接继承自 object 类。
3.3 多态
3.3.1 定义
(1) 字面意思:对于一种行为有不同表现形态。
(2) 概念:对于父类的一个方法,在不同的子类上有不同体现。
(3) 说明:编码时调用父类方法,运行时传递子类对象执行子类方法。
3.3.2 重写
(1) 定义:在子类定义与父类相同的方法。
(2) 作用:改变父类行为,体现子类个性。
(3) 算数运算符
(4)复合运算符重载
注:+和+=不一样
+=内部调用__iadd__,会返回自身对象
+内部调用__add__,会返回新对象
(5) 比较运算重载
''' 只需要定义好eq和gt其他的会自动匹配'''
class Vector(object):
def __init__(self,x,y):
self.x = x
self.y = y
def __eq__(self, other):
return self.x == other.x and self.y == other.y
pos1 = Vector(1,1)
pos2 = Vector(1,1)
#== 是按照eq去比较
print(pos1 == pos2)
# is是按照地址去比较
print(pos1 is pos2)
#Python语言的内存优化机制
#对象池:创建对象是,会判断池中是否具有相同的对象,如果有会返回地址,如果没有会开辟空间
#类型有__eq__函数,按照内容比较
#没有__eq__函数,按照地址比较
a = ['a','b']
b = ['a','b']
print(a == b)
print(a is b)
print(['A'] == ['A'])
四、MVC架构
经典MVC架构中,M是模型(model) V是视图(view) C是控制器(contrller)
from typing import List
class StudentModel:
'''学生数据模型:封装View与controller之间的数据'''
def __init__(self, name='',age=0,score=0,sid=''):
self.name = name
self.age = age
self.score = score
self.sid = sid
class StudentView:
''' 学生视图,处理界面逻辑 输入输出'''
def __init__(self):
self.controller = StudentController()
def display_menu(self):
print("按1键录入学生信息")
print("按2键显示学生信息")
print("按3键删除学生信息")
print("按4键修改学生信息")
def select_menu(self):
number = input("请输入:")
if number == '1':
#重点1:本类调用实例方法
self.input_student()
elif number == '2':
self.display_student()
def input_student(self):
#重点2:每次使用新Model存储学生信息
model = StudentModel()
model.name = input("请输入学生姓名")
model.age = input("请输入学生年龄")
model.score = input("请输入学生分数")
#重点3:每次使用旧的contrller添加学生信息
self.controller.add_student(model)
def display_student(self):
for st in self.controller.list_student:
print(f'{st.name}的年龄为{st.age},成绩是{st.score}')
class StudentController:
'''
学生控制器:负责核心功能的算法
'''
def __init__(self):
self.list_student = [] #type:List[StudentModel]
self.sid = 1001
def add_student(self,new):
#自增长的数
new.sid = self.sid
self.sid += 1
self.list_student.append(new)
view = StudentView()
while True:
view.display_menu()
view.select_menu()