python数据类型、编码
一、数字类型使用
可变与不可变类型
- 可变:在值改变的情况,如果id不变,证明就是在修改原值,即可变类型
- 不可变:在值改变的情况,如果id也跟着变,证明根本没有修改原值,即不可变类型
int基本使用
1.常用操作+内置方法
算数运算,比较运算
2.该类型总结
- 存一个值
- 不可变类型
x=10 print(id(x)) x=11 print(id(x))
float基本使用
1.常用操作+内置方法
算法运算,比较运算
2.该类型总结
- 存一个值
- 不可变类型
x=10.1 print(id(x)) x=11.1 print(id(x))
二、字符串使用
str基本使用
1.常用操作+内置方法
索引取值
(正向取+反向取):只能取
msg="hello world" print(msg[1]) print(msg[5]) print(msg[-1]) print(msg[-3])
切片
从一个大字符串中切除一个子字符串(顾头不顾尾,步长)
msg="hello world" print(msg[1:3]) print(msg[6:11]) print(msg[6:11:2]) #world #wrd # 倒着取值(了解):注意方向要一致 print(msg[6:]) print(msg[-1:-6:-1]) print(msg[-1::-1]) print(msg[::-1])
长度len
msg="hello world" print(len(msg)) # 长度是11,索引最大到10
成员运算in 和not in
判断一个子字符串是否存在于一个大字符串中
msg="hello world hello momo" print('momo' in msg) print('world' in msg) print('hello' not in msg) print(not 'hello' in msg)
移除空白strip
msg=' mogu ' res=msg.strip() # 默认去除的是字符串左右两边的空格 print(msg) print(res) # strip会从左往右开始吃空格,直到碰到一个非空格为止 # 右面相同的原理 #ps:strip并没有修改原值,是产生一个新值 msg='******mo****gu*****' print(msg.strip('*')) msg='-&!^%aaaa-!&^%' print(msg.strip('!-&^%'))
切分split
把一个字符串按照某种分隔符切成一个列表
info='root:x:0:0:admin user:/root:/bin/bash' res=info.split(':',maxsplit=-1) print(res,type(res)) print(res[0])
l=['mogu',123,'chimogu']
s1=':'.join(l) #把列表又转成了字符串(前提是列表中所有元素均为字符串)
print(s1,type(s1))
循环
while循环取值
1 msg='hello world' 2 i=0 3 while i < len(msg): 4 print(msg[i]) 5 i+=1
for循环取值
msg='hello world' for item in msg:
print(item)
大小写切换
# 2、lower,upper print('aaAbCCC'.lower()) print('aaAbCCC'.upper())
判断以什么开头(startswith)什么结尾(endswith)
print('xiaomogu like mogu'.startswith('xiao')) print('xiaomogu like mogu'.endswith('gu'))
格式化输出format
print('my name is %s my age is %s' %(18,'mogu')) print('my name is {name} my age is {age}'.format(age=18,name='mogu')) print('my name is {} my age is {}'.format(18,'mogu')) print('my name is {0}{0}{0} my age is {1}'.format(18,'mogu'))
replace 替换操作
msg='my name is xiaomogu,xiaomogu say hello' print(msg.replace('xiaomogu','xiaonvhai',1))
isdigit
只有在字符串中包含纯数字的情况下结果才为True
print('10123'.isdigit())
其他
#center,ljust,rjust,zfill 分别对应中央位 左对齐 右对齐 右对齐以0为占位符 print('**************%s*************************' %'mogu') print('mogu'.center(50,'*')) print('mogu'.ljust(50,'=')) print('mogu'.rjust(50,'-')) print('mogu'.rjust(50,'0')) print('mogu'.zfill(50))
# expandtabs end=' ' 取消print默认的换行符\n print('aaabbbb',end=' ') print('cccc',end='') print('aaaa\nbbbb',end='') print('aaa\tbbb'.expandtabs(tabsize=3))
#\n 代表换行符 \t 代表tab键 (制表符)
总结
- 存一个值
- 有序
- 不可变
三、列表使用
list基本使用
list类型转换的工作原理:list(items)
1、先造一个空列表
2、类似调用了一个for循环,从items里取出一个值放入空列表中,循环往复直到取干净为止
1.常用操作+内置方法
按索引存取值
(正向存取+反向存取):即可以取也可以改
ps:不能根据索引往列表里新加入值
l=['a','b','c','d'] print(l[3]) print(l[-1]) l[3] = 'D' print(l)
切片
从一个大列表中切出一个子列表(顾头不顾尾,步长)
l=['a','b','c','d'] l1=l[1:3] print(l1)
len 长度
print(len(l))
成员运算in和not in
names=['mogu','nvhai','huochai',1,3,4] print(4 in names) print(5 not in names)
追加、插入
##append 追加值(放到末尾) insert(索引,值) l=['a','b','c','d'] l.append('aaa') print(l) l.insert(0,'B') #['B', 'a', 'b', 'c', 'd'] l.insert(0,'mogu') print(l)
删除
l=['a','b','mogu','d'] del l[2] # 非字符串独有的删除,是一种通用的删除方式 del print(l) res=l.remove('alex') # 单纯的删除,没有返回值 remove print(l) print(res) #pop 从列表中拿走一个值: # 1、删除一个元素 # 2、将该元素当做返回值返回 res=l.pop() # 默认从最后一个删除 print(l) print(res) res=l.pop(2) print(res)
循环
l=['a','b','c'] for item in l: #循环取值 print(item)
排序 sort
a=[[1,2],[3,4],[5,6],[7,8],[9,0]] b=[8,7,9,7,9] a.sort() b.sort()
l1=[1,2.3,'a','a','b','a'] print(l1.count('a')) #count 次数 l2=[4,5,6] l1.append(l2[0]) l1.append(l2[1]) l1.append(l2[2])#append到l1的末尾 l1.extend(l2)#extend 把多个值往末尾放 print(l1) l1=[1,2.3,'a','a','b','a'] l1.index('egon') # index 查找 找不到会报错 print(l1.index('a',0,3)) names=['mogu','nvhai','huochai'] names.reverse() #reverse 将列表翻转 print(names) nums=[9,3,4,-1,5,100,98] nums.sort() # 默认从小到大排序 sort nums.sort(reverse=True) # 翻转过来从大到小排序 print(nums)
队列与堆栈
#队列:先进先出 l=[] # 入队 l.append('first') l.append('second') l.append('third') print(l) # 出队 print(l.pop(0)) print(l.pop(0)) print(l.pop(0))
# 堆栈:先进后出 l=[] # 入栈 l.append('first') l.append('second') l.append('third') print(l) # 出栈 print(l.pop(-1)) print(l.pop(-1)) print(l.pop(-1))
总结
- 存多个值
- 有序
- 可变类型
四、元组使用(不可变列表)
tuple基本使用
元组的定义:不可变的列表 ,用( )内用逗号分隔开多个任意类型的元素
t=('a',1,3.3) #t=tuple(('a',1,3.3)) print(t,type(t)) #class tuple
1. 常用操作+内置方法
1.1 按索引取值(正向取+反向取):只能取
t1=tuple('hello') # 任意可以被for循环的数据类型都可以被tuple转成元组 print(t1,type(t1)) t1=('hello','world') # 任意可以被for循环的数据类型都可以被tuple转成元组 print(t1,type(t1)) print(t1[1])
1.2 切片(顾头不顾尾)
t1=(1,2,3,4,5) print(t1[0:3])
1.3 长度len
与列表操作一致
1.4 循环
与列表操作一致
2.该类型总结
- 存多个值
- 有序
- 不可变类型
- ps :元组可变指的元组内索引对应的内存地址不变,列表可变指的列表内索引对应的内存地址可以改变
五、字典使用
dict基本使用
字典用途是存多个种类不同的值,在{ } 内用逗号分隔开多个元素,每一个元素都是key:value的形式,key应该对value有描述性的功能
ps:注意:value可以是任意类型,而key必须是不可变类型且唯一
name_dic={ 'name':'xiaomogu', 'age':19, 'hobby':'learning' }
常用操作内置方法
按key存取值
可存可取
name_dic={ 'name':'xiaomogu', 'age':19, 'hobby':'learning' } print(id(name_dic)) name_dic['age']=20 print(id(name_dic)) print(name_dic)
长度len
name_dic={ 'name':'xiaomogu', 'age':19, 'hobby':'learning' } print(len(name_dic))
成员运算in 和not in判断的是字典的key
name_dic={ 'name':'xiaomogu', 'age':19, 'hobby':'learning' } print('age'in name_dic)
删除
name_dic={ 'name':'xiaomogu', 'age':19, 'hobby':'learning' } res=name_dic.pop('hobby') #删除key对应的元素,返回value值 print(res)
键keys() 值values() 键值对 items()
name_dic={ 'name':'xiaomogu', 'age':19, 'hobby':'learning' } print(name_dic.keys()) print(name_dic.values()) print(name_dic.items()) print(list(name_dic.keys())) print(list(name_dic.values())) print(list(name_dic.items()))
循环
name_dic={ 'name':'xiaomogu', 'age':19, 'hobby':'learning' } for k in name_dic.keys(): print(k) for k in name_dic: print(k,name_dic[k]) for v in name_dic.values(): print(v) for k,v in name_dic.items(): #k,v=('name', 'egon') print(k,v)
get 取值
name_dic={ 'name':'xiaomogu', 'age':19, 'hobby':'learning' } res=name_dic.get('sex',None) print(res) #None res1=name_dic.get('name',None) print(res1) #xiaomogu
其他操作
# 需要掌握 name_dic={ 'name':'xiaomogu', 'age':19, 'hobby':'learning' } res=name_dic.popitem() print(name_dic,res) #{'name': 'xiaomogu', 'age': 19} ('hobby', 'learning') name_dic.update({'x':1,'height':1.78}) # 老字典d没有的则添加,有的则以新字典为准进行修改 print(name_dic) #{'name': 'xiaomogu', 'age': 19, 'x': 1, 'height': 1.78}
总结
- 存多个值
- 无序
- 可变类型
六、集合的使用
set基本使用
集合用于:1.去重 2 .关系运算
s={1,2,1,1,1,1,1,1,1} #s=set({1,2}) print(type(s)) print(s)
1.常用操作+内置方法
关系运算
#关系运算 english_class={'xiaomogu','xiaohuochai','张三','张四','李五','关二爷'} computer_class={'xiaomomo','xiaohuochai','张三','mogu','李五','xiaomogu'} # 1.1、求既报名English又报名computer的学生有哪些->即求两个集合体的共同部分,称之为交集 print(english_class & computer_class) #{'李五', 'xiaomogu', '张三', 'xiaohuochai'} #1.2、求只报名English,没有报名computer的学生有哪些->即求English减去computer,称之为差集 print(english_class - computer_class) #{'张四', '关二爷'} #1.3、求只报名computer,没有报名English的学员有哪些 print(computer_class - english_class) #{'xiaomomo', 'mogu'} #1.4 求所有报名的学生姓名->即求两个集合体的总和,称之为并集 print(english_class | computer_class) #{'xiaohuochai', 'mogu', '张四', 'xiaomogu', '张三', '李五', 'xiaomomo', '关二爷'} #1.5 求没有同时报名两门课程的学生姓名->称之为对称差集 print(english_class ^ computer_class) #{'关二爷', '张四', 'xiaomomo', 'mogu'} # 1.6 == s1={1,2,3} s2={3,2,1} print(s1 == s2) # 注意:只有在两个集合存在包含与被包含的关系时才可以进行大小的比较 # 1.7、父集:>,>= s1={1,2,3} s2={1,2} print(s1 > s2) # s1是s2的父集 print(s1 >= s2) # s1是s2的父集 print(s1.issuperset(s2)) #s1 >= s2 s3={1,2,3} s4={3,4,5,6} print(s4 >= s3) # 1.8、子集:<,<= print(s2.issubset(s1)) #s2 <= s1 print(len({1,2,3})) print(1 in {1,2,3})
# 集合其他的内置方法 s1={1,2,3,4,5} print(id(s1)) s1.add(6) print(s1) print(id(s1)) s2={3,4} s1.difference_update(s2) ## s1=s1.difference(s2) #s1=s1 - s2 print(s1) s3={6,7} print(s1.isdisjoint(s3)) # 删除 print(s1.pop()) # 随机删除 s1.discard(333333) # 指定元素删除,,如果元素不存在也不报错 s1.remove(3333) # 指定元素删除,如果元素不存在则报错 print(s1) s1={1,2,3,4,5} s1.update({3,4,5,6,7}) s1.update('hello') print(s1)
去重
局限性:1.不能保证原来的顺序 2.不能针对可变类型去重
l=[1,1,1,1,'mogu','xiaohuochai','mogu'] s=set(l) #{1,'egon','alex'} print(s) l=list(s) #[] print(l)
# 需求: #1、列表内的元素有可变类型 #2、去重之后要保持原来顺序 info=[ {'name':'xiaomogu','age':18}, {'name':'momo','age':23}, {'name':'xiaonvhai','age':17}, {'name': '张三', 'age': 46}, {'name':'李四','age':52}, {'name':'xiaomogu','age':18}, ] d=[] for dic in info: if dic not in d: d.append(dic) info=d print(info)
循环
s={'xiaomogu','momo','xiaonvhai','xiaohuochai'} for item in s: print(item)
七、字符编码
Python解释器的执行原理
执行Python文件三个阶段
1.先启动Python解释器
2.Python解释器将name.py文件内容当做普通字符读入内存
3.Python解释器解释执行读入内存的代码,识别Python语法
notepad++读取Python文件三个阶段
1.先启动notepad++
2.notepad++将name.py文件的内容当做普通字符读入内存
3.notepad++将读入内存的字符打印到屏幕上
总结
执行Python的程序前两个阶段与文本编辑器的原理一样
只有第三个阶段才开始识别Python语法:
n=1000
Python解释器执行Python文件在第二到第三阶段涉及字符的概念,会用到字符编码
1.什么是字符编码
字符编码表就是一个存有字符与数字对应关系的表
人类字符------->编码 encode -------->数字
人类字符<-------解码decode<---------数字
8bit = 1bytes
ASCII : 8个二进制位(1bytes)对应一个英文字符
A------>0001
GBK :16二进制位(2bytes)对应中文字符,8个二进制位(1bytes)对应一个英文字符
a 00 , b 01 , c 10 , d 11
中------>111
Shift-JIS : 何------>001
Unicode:统一用2bytes对应符号
特点:1、Unicode 数字<------->字符
2、Unicode 数字<-------->其他编码的数字
解决两个问题: 1、兼容万国字符
2、与各国的编码都有对应关系
重点
1、内存中固定使用Unicode,不能改
2、可以修改硬盘的编码
Unicode---------->编码encode---------->GBK
Unicode<----------解码decode<-----------GBK
utf-8 : 全程Unicode Transformation Format
1bytes代表一个英文字符
3bytes代表一个中文字符
结论
但凡出现乱码问题,一定是编码的时候用了一套标准,而解码的时候用了另一套标准
解决乱码问题的核心: 编码的时候用什么编码,解码的时候就用什么解码
Python3默认使用编码utf-8
Python2默认使用ASCII
文件头的作用:告知Python解释器读文件时应该用什么编码
#coding=utf-8
#coding:utf-8 x='上' res1=x.encode('gbk') #unicode----编码----->gbk res2=x.encode('utf-8') #unicode----编码----->gbk print(res1,type(res1)) print(res2,type(res2)) # unicode<----编码decode----->gbk print(res1.decode('gbk'))
八、文件处理
1.什么是文件:文件是操作系统为应用程序或用户提供的一个操作硬盘的虚拟的单位。
2.为什么要用文件:应用程序中需要经常将内存中的数据永久保存,而应用程序无法直接操作硬盘
只能通过操作系统提供的虚拟单位去间接地操作硬盘
3.如何用文件
Python的open操作:1.向操作系统发送打开文件的请求
2.在应用程序拿到一个返回值,改值指向操作系统打开的文件
f=open(r'D:\a.txt',mode='r',encoding='utf-8') # f=>应用程序中的一个值=>操作系统打开的文件a.txt=>硬盘中的一块空间 data=f.read() print(data) del f f.close() # 向操作系统发送关闭文件的请求 print(f) f.read()
总结
文件处理的步骤:1.打开文件 2.读/写文件 3 . 关闭文件
ps:with open操作
with open(r'a.txt',mode='r',encoding='utf-8') as f,\ open('b.txt',mode='r',encoding='utf-8') as f1: #文件处理的代码块 pass
九、文件的打开模式
文件的打开模式有三种
r:只读模式(默认)
w:只写模式
a:只追加写
控制操作文件内容的模式有两种(不能单独使用,必须与上述3种其中之一连用)
t:(默认)text文本模式,该模式下操作文件内容的单位都是字符串,该模式只适用于文本文件 ps:该模式必须指定encoding='某种字符编码'
b:bytes二进制模式,该模式下操作文件内容的单位都是bytes,该模式适用于所有类型的文件
1、r模式:只读(默认)
文件不存在则报错;文件存在,并且文件指针调到文件开头
with open('a.txt',mode='rt',encoding='utf-8') as f: data1=f.read() print(type(data1)) print('第一次:',data1) #第一次全部读取完毕 data2=f.read() print('第二次',data2) #第二次为空
with open('a.txt', mode='rt', encoding='utf-8') as f: line1=f.readline() #readline 一次只读取一行,指针跳到第二行开头 print(line1,end='') print('====>') line2 = f.readline()#readline 一次只读取一行,指针跳到第二行开头 print(line2, end='') with open('a.txt', mode='rt', encoding='utf-8') as f: l=f.readlines()#一次性全部读取,包括换行符\n for i in l: print(i,end='') print(l,type(l))
2、w模式:只写模式
文件不存在则创建空文档,并且文件指针跳到文件的开头
文件存在,会将内容清空,并且文件指针跳到文件的开头
ps:如果每次都是重新打开文件,那么文件的内容总会清空,指针跳到开头
如果在打开文件不关闭的清空下,连续的写入,本次写入会基于上一次指针所在位置往后继续写
with open('c.txt',mode='wt',encoding='utf-8') as f: #不关闭文件的清空下连续的写入 f.write('hello\n') f.write('小蘑菇\n') l=['123\n','啦啦啦\n','卖女孩的小火柴\n'] for line in l: f.write(line) f.writelines(l)
3、a模式:只追加写入
文件不存在则创建一个空文档,并且文件指针跳到文件的末尾
文件存在,也会将文件指针跳到文件的末尾
x=str(100-50) with open('a.txt',mode='at',encoding='utf-8') as f: print(f.readable()) print(f.writable()) # f.read() 无法读取 f.write('100') f.writelines([x,'\n'])
#读取文件的内容转换类型进行数学运算 with open('a.txt',mode='rt',encoding='utf-8') as f1: res=f1.readline() res2=f1.readline() print(res) print(res2) res3=int(res)+int(res2) print(res3)
4、b模式
bytes二进制模式,该模式下操作文件的内容的单位都是bytes,该模式适用于所有的文件类型
ps:一定不能指定encoding参数
with open('1.mp4',mode='rb') as f: data=f.readline() print(data,type(data))
with open('d.txt',mode='rb') as f: data=f.read() # print(data,type(data)) #二进制模式 res=data.decode('utf-8') #读取需指定解码的编码类型 print(res)
# 遍历文件内容的方式 with open('d.txt',mode='rt',encoding='utf-8') as f: for line in f: #line='bbb\n' print(line,end='')
十、文件内指针的移动
文件内指针的操作:f.seek
第一个参数:控制移动的字节数
第二个参数:控制移动的参照物,值可以为0(t、b模式都可以用)、1、2(1(文件的中间)2(文件的末尾)只能在b模式下使用)
with open('e.txt',mode='rt',encoding='utf-8') as f: f.seek(6,0) # 单位是字节 print(f.read()) #移动6个字节后读取 f.read() f.seek(0,0) #又将指针移动到了开头 print('第二次',f.read())
#read的n在t模式下代表的是字符个数 #read的n在b模式下代表的是字节个数 with open('e.txt',mode='rb') as f: data=f.read(3) #读取3个字节,即为一个中文字符 print(data.decode('utf-8'))
十一、文件的修改
一、文本编辑器修改文件的原理
1、先将文件内容全部读入内存
2、在内存中修改完毕
3、将修改的结果覆盖写回硬盘
优点:在修改期间硬盘上同一时刻只有一份数据
缺点:占用内存过高
with open('db.txt',mode='rt',encoding='utf-8') as f: data=f.read() new_data=data.replace('蘑菇','小蘑菇') #替换 print(new_data) with open('db.txt',mode='wt',encoding='utf-8') as f: f.write(new_data)
一行行的读,一行行的改
1.以读的模式打开源文件,以写的模式打开一个临时文件
2.然后用for循环读取原文件一行行的内容,每读一行则修改一行,将修改的结果写入临时文件,直到把源文件都遍历完
3.删除原文件,将临时文件重命名为原文件名
优点:同一时刻在内存中只存在文件的一行内容
缺点:在修改期间硬盘上同一份数据会有两份
import os with open('db.txt',mode='rt',encoding='utf-8') as src_f,\ open('.db.txt.swap',mode='wt',encoding='utf-8') as temp_f: for line in src_f: if '要修改的内容' in line: line=line.replace('同上内容','小蘑菇') temp_f.write(line) os.remove('db.txt') os.rename('.db.txt.swap','db.txt')
# 此操作用于删除特定内容所在的行 with open('db.txt','rt',encoding='utf-8')as f: lines=f.readlines() with open('db.txt', 'wt', encoding='utf-8')as f1: for line in lines: if 'dsb' in line: #如果内容在这行 将删除这行,别的行不动 continue f1.write(line)
练习
打印金字塔
# #max_level=5 # * #current_level=1,空格数=4,*号数=1 # *** #current_level=2,空格数=3,*号数=3 # ***** #current_level=3,空格数=2,*号数=5 # ******* #current_level=4,空格数=1,*号数=7 # ********* #current_level=5,空格数=0,*号数=9 #数学表达式 # 空格数=max_level-current_level # *号数=2*current_level-1 max_level=int(input('数字: ')) for current_level in range(1,max_level+1): for i in range(max_level-current_level): print(' ',end='') for l in range(2*current_level-1): print('*',end='') print()
三级菜单
#要求: # 打印省、市、县三级菜单 # 可返回上一级 # 可随时退出程序 menu = { '北京':{ '海淀':{ '五道口':{ 'soho':{}, '网易':{}, 'google':{} }, '中关村':{ '爱奇艺':{}, '汽车之家':{}, 'youku':{}, }, '上地':{ '百度':{}, }, }, '昌平':{ '沙河':{ '老男孩':{}, '北航':{}, }, '天通苑':{}, '回龙观':{}, }, '朝阳':{}, '东城':{}, }, '上海':{ '闵行':{ "人民广场":{ '炸鸡店':{} } }, '闸北':{ '火车站':{ '携程':{} } }, '浦东':{}, }, '山东':{}, } tag=True while tag:#一级菜单 menu1=menu for name in menu1:#打印第一层 print(name) diyi=input('第一层>>>: ').strip() if diyi=='q':#输入q则退出 tag=False if diyi not in menu1: continue while tag:#二级菜单 menu2=menu1[diyi]#menu[diyi] for name in menu2:#打印第二层 print(name) dier=input('第二层>>>: ').strip() if dier == 'b': break#输入b则返回上一层 if dier == 'q':#输入q则退出 tag=False if dier not in menu2: continue while tag:#三级菜单 menu3=menu2[dier]#menu[diyi][dier] for name in menu3:#打印第三层 print(name) disan=input('第三层>>>: ').strip() if disan == 'b': break#输入b则返回上一层 if disan == 'q':#输入q则退出 tag=False if disan not in menu3: continue while tag:#四级菜单 menu4=menu3[disan]#menu[diyi][dier][disan] for name in menu4:#打印第四层 print(name) disi=input('第四层>>>: ').strip() if disi == 'b': break#输入b则返回上一层 if disi == 'q':#输入q则退出 tag = False if disi not in menu4: continue
实现简单购物车
#用户名和密码存放于文件中,格式为: #启动程序后,先登录,登录成功则让用户输入工资,然后打印商品列表,失败则重新登录,超过三次则退出程序 #允许用户根据商品编号购买商品 # 用户选择商品后,检测余额是否够,够就直接扣款,不够就提醒 # 可随时退出,退出时,打印已购买商品和余额 #用户列表 mogu|123 product_list = {'1':['Iphone7',5800], '2':['Coffee',30], '3':['疙瘩汤',10], '4':['Python Book',99], '5':['Bike',199], '6':['ViVo X9',2499]} d=product_list #前期定义 tag=True shopping=[] with open('用户列表',mode='rt',encoding='utf-8')as user:#打开用户列表准备读取 res=user.read().split('|')#读取按照'|'进行切分 name=res[0]#读0号索引字符,赋值给name pwd=res[1]#读1号索引字符,赋值给pwd n=1 while tag:#第一层循环开始 if n==3:#如果错误3次则退出 tag=False inp_name=input('输入您的用户名:').strip() if not inp_name or inp_name not in name:#判断输入字符与name的关系 print('用户名不存在!') continue inp_pwd=input('输入您的密码:').strip() if inp_pwd==pwd:#判断输入字符与pwd的关系 print('登录成功!!!') else: print('您输入的密码有误!') n+=1 continue while tag:#第二层循环开始 wage=input('请输入您的工资:').strip()#第一次的金额 if not wage.isdigit():#判断输入的是否是数字 print('请输入数字') continue with open('余额', mode='wt', encoding='utf-8') as gongzi:#第一次新建文件‘余额’ gongzi.write(wage)#写入之前输入的wage for k, v in d.items(): # k,v=('编号', '子列表') print(k,'',v)#循环打印字典的k,v while tag:#第三层循环开始 print('q:退出') choice = input('购买商品:').strip() if choice=='q':#退出机制 tag=False break if not choice or choice not in d:#判断输入字符与商品列表关系 print('输入错误,请重新输入!') continue count = input('购买数量:').strip() if not count.isdigit():continue#判断count是否为数字 wage1=int(d[choice][1])*int(count)#计算选择的商品乘数量后的价格 with open('余额', mode='rt', encoding='utf-8') as f1:#选择商品后再次读取余额 wage2=int(f1.read()) if wage1 > wage2:#用户选择商品后,检测余额(作比较),够就(余额-商品金额)不够就提醒 print('余额不足!') continue shopping.append(('商品',d[choice],'数量',count)) #选择一次商品计算一次(工资减商品金额=余额 存入文件) with open('余额', mode='rt', encoding='utf-8') as balance:#第二次读取余额文件 yue=balance.read()#读取余额赋值给yue with open('余额',mode='wt',encoding='utf-8') as balance1:#第二次写入计算结果至余额文件 balance1.write(str(int(yue)-wage1)) with open('余额', mode='rt', encoding='utf-8') as ff:#第二次读取计算后的余额赋值给rse rse=ff.read() print('已购买',shopping,'余额',rse)