周末回顾 :文件、函数、名称空间、装饰器、递归函数、生成式、可迭代(迭代器)对象
周末回顾 10.8 - 10.14
目录
一、文件
1.什么是文件
文件:文件是操作系统提供给应用程序来操作硬盘的虚拟概念。
数据都保存在硬盘中,应用程序想要对其进行操作,在操作系统中就出现了文件的概念。从而应程序能够通过操作系统去对硬盘进行调用。
2.文件操作的流程
-
1文件操作的流程
文件操作的流程:打开文件>>>调用文件>>>>关闭文件
1.打开文件
关键字 open(要打开的文件的路径,操作模式,encoding编码方法)
open可以由应用程序通过操作系统打开硬盘中对应的文件路径,按照指定模式操作,并返回一个文件对象
# open返回的是文件对象
# 文件路径中由于撬棍\和字母组合有特殊用法,所以在路径的字符串前加上r''更加严谨
2.调用文件
f.read 读文件
f.write 写文件
3.关闭文件
f.cloes 关闭文件
-
2资源回收与with方法
1.资源回收
资源分为两部分 1 应用程序接收的变量名 f 2 操作系统打开的文件
资源回收就是回收这两部,
一个用 1 f.close来回收系统调用的f,
一个用 2 del f 回收应用文件级别的文件
而 del f 要在 f.close 之后,否则无法回收,所以有了with上下文管理方法来操作文件
2.with上下文管理方法
with方法不需要 close方法和 del f,就可以自动帮我们关闭文件的调用
# 语法
with open(要打开的文件的路径,操作模式,指定编码方法) as 变量名f:
with体代码
# with还支持打开多个文件,每个open关键字中间用逗号隔开
3.文件的操作模式
-
1文件的读写模式
1.r模式,只读模式只能读不能写
# 如果操作的文件路径不存在则会报错
2.w模式,只能写不能读,每次用w模式打开文件都会清空文件中的内容,重新写入
# 如果操作的文件路径不存在则会自动创建
3.a模式,可读可写,写的内容只在尾部追加
# 如果操作的文件路径不存在则会自动创建
-
2文件的操作模式
1.t模式文本模式
只能操作文本文件,并对文本文件进行读写操作,而且要指定字符编码模式
2.b模式二进制模式
可以操作任意类型的文件,并且必须不能指定字符编码模式
3.操作文件的方法
-
1需要掌握的方法
# 用f来统一代替变量名
1.读操作
1) f.read() 一次性读取文件中所有的内容
2) f.readline() 按行读取文件中的内容,结束之后光标跳转至第二行开头
3) f.readlines() 一行行的读取文件中的全部内容,结束之后光标跳转至文件末尾
2.写操作
1) f.write()
对t文本模式写入数据的时候,可以不指定字符编码模式
对b二进制模式的是写入数据,必须要指定字符编码模式
# f.write(r'userinfo.txt',encoding='utf8')
2) f.writelines()
对t文本模式,是接收一个列表,一次性写入全部内容
对b二进制模式,需要先将写入的内容用 bytes()转换为字节串
# f.writelines([bytes('111\n',encoding='utf8'),'111\n'.encode('utf8')])
-
2需要了解的方法
1. f.readable() # 判读文件是否可读
2. f.writeable() # 判读文件是否可写
3. f.closed() # 判读文件是否关闭
4. f.encoding() # 文件字符编码,b模式没有
5. f.flush() # 相当于 ctrl + s 保存
4.文件内光标的移动
文件内有指针的概念,用来操作文件内的读写。 # 操作以字节为单位,t模式下以字符为单位
1. seek(offset,whence)方法
offset:指针的移动字节
whence:操作的模式 0模式是默认模式,从文件开头操作
1模式,从当前位置曹祖
2模式,从文件末尾操作
2. tell()方法 告诉我们指针的位置
5.文件的修改
-
1计算机硬盘修改数据的原理
硬盘修改数据不是直接修改或者增减,而是覆盖了旧的数据
-
2文件内容修改
1.覆盖写 # 先读取文件数据,在替换其中的内容
with open(r'a.txt','r',encoding='utf8') as f:
data = f.read() # 先读取文件a.txt
with open(r'a.txt', 'w', encoding='utf8') as f1:
f1.write(data.replace('jason', 'tony')) # 在内存中修改a.txt文件
2.换地方写 # 先读取文件数据,在内存中建立临时文件,再将原文件删除,将临时文件以原文件的名称保存
import os
with open(r'a.txt','rt',encoding='utf8') as read_f,\ open(f'a.txt.swap','w',encoding='utf8') as write_f:
for line in read_f:
write_f.write(line.replace('tony', 'kevin'))
os.remove('a.txt')
os.rename('.a.txt.swap','a.txt')
二、函数
1.什么是函数
-
1函数的定义
函数是一种存放代码体的容器,它具备一定处理数据的功能
1.定义函数# 函数的使用必须 先定义 再调用
定义函数,相当于将函数名绑定函数体代码,当我们调用函数时,相当于通过函数名调用此段函数体代码
2.函数的语法
def 函数名(参数):
'''函数注释'''
函数体代码
return 返回值
'''
def 是定义函数的关键字 函数名应该见名知意,需要表达函数的功能
参数是我们可以通过其向函数内部传数据
函数注释是帮助我们来对函数功能进行描述的
函数体代码是函数功能实现的主要核心诶人
return 返回值是返回调用者的数据值
'''
-
2函数的分类
1.空函数 函数体代码为 pass 或者 ...
# 用在项目搭建和项目框架前期
2.有参函数
参数是向函数体代码传递数据的中介
3.无参函数
没有参数的函数
2.调用函数与函数的返回值
- 1调用函数
1.定义函数时只检测语法
2.调用函数才执行函数体代码
调用函数 直接用函数名加括号
index()
- 2函数返回值
1.什么是函数的返回值 如何获取
函数的返回值是函数返回给调用者的结果 用 return来定义
用一个变量名来接收函数调用的返回值
变量名 = 函数名()
2.返回值的情况
没有 return 返回 None
拥有 return + 没有东西 返回 None
+ something 返回 something
+ 单个数据 返回 单个数据
+ 多个数 返回 包含多个数据的元组
# 函数体代码遇到return则立即结束 返回return后面的内容
3.函数的参数
-
1形式参数与实际参数
1.形式参数'形参'
定义阶段括号内的参数
2.实际参数'实参'
调用阶段括号内的参数
-
2位置参数
1.位置新参,在定义阶段 从左到右的顺序定义的参数叫做位置形参,位置形参必须要被传值
2.位置实参,在调用阶段,从左到右的顺序调用的参数叫做位置实参,位置实参会被按照顺序传给位置形参
def func1(a, b): # a b为位置形参
print(a)
func1(1, 2) # 1 2 为位置实参,位置实参的数量必须和位置形参保存一直,而且传参时也是按照位置来传递数据值的
-
3关键字参数
key = value 这种形式的传参,叫做关键字参数,关键字参数可以打破位置传参的顺序,将想要传递的数据值直接指定给某个位置形参
# 参数的排列顺序是 由简单到复杂,从数量少到数量多
1.关键字传参一定要在位置参传参后面,在位置传参之前不符合参数的排列顺序 会报错
2.关键字传参只能给一个位置形参传递一个数据值,多了会报错
3.关键字传参可以传数据值,也可以穿变量名
#
name = 'duoduo'
def func1(a, b,c): # a b为位置形参
print(a,b,c)
func1(2, b=1, c = name) # 关键字参数在位置实参后面,且可以传递变量名
-
4默认参数
默认参数的本质:关键字形参 # 当一个数据的重复出现时,可以定义成默认参数,调用相同的参数时后续不必传参,需要修改时再传参
name = 'jason'
def func1(a, b, c='duoduo'): # a b为位置形参
print(a, b, c)
1 实参和默认形参一致时不用传参
func1(2, b=1) # 2 1 duoduo
2 实参和默认形参不一致时 用关键字传参
func1(2, b=1, c='lulu') # 2 1 lulu
func1(2, b=1, c=name) # 2 1 jason
-
5可变长的形参
在定义阶段,用带*形参 来接收多余的位置实参,用带**形参 来接收多余的关键字参数
1. *args 接收多余的位置实参
会自动接收多余的位置实参,并将其以元组的形式保存起来
2.**kwargs 接收多余的关键字参数,并将其以字典中键值对的形式保存起来
def func1(a, *b,**c):
print(a, b, c)
func1() # 会报错,当参数中有位置形参时,必须有位置实参传给他
func1(1) # 1 () {} 有实参传递给位置形参后,会生成一个空元组和一个空字典
func1(2, b=1) # 2 () {'b': 1}
func1(2, b=1, c='lulu') # 2 () {'b': 1, 'c': 'lulu'}
-
6可变长的实参
在函数调用阶段,用* 和** 将数据集中的数据打散
1.*args 将数据集中的元素,按照位置顺序传递给函数体代码
2.**kwargs 将字典打散成关键字参数,并按照顺序将其传递给函数体代码
name_l = ['jason', 'duo', 'qiu']
name_d = {'name': 'duo', 'age': 12, 'hobby': 'lol'}
# 举例
def func1(a, b, c):
print(a, b, c)
def func2(name,age,hobby):
print(name,age,hobby)
func1(*name_l) # jason duo qiu
func2(**name_d) # duo 12 lol 字典中的键需要和位置形参一致,且数量也一致才能传递给位置形参
参数的顺序是:
位置参数、默认参数(关键字形参)、*args、命名关键字参数、**kwargs
4.函数名的多种用法
-
1可以当变量名
函数名可以当作绑定了函数体代码的变量名,赋值给别的变量名之后,别的变量名也可以调用该函数体代码
def func1():
print('咖啡苦不如命苦')
index = func1
index() # 咖啡苦不如命苦
-
2可以当函数的参数
可以当作参数传值进去
# 举例
def func1():
print('咖啡苦不如命苦')
def func2():
print('天天开心')
def index(a):
a() # 该函数可以调用别的函数
# 修改参数可以调用不同的函数
index(func1) # 咖啡苦不如命苦
index(func2) # 天天开心
-
3可以当函数的返回值
函数名还可以为其他函数的返回值,当有变量名接收的时候,调用其变量名则可以调用该函数
1)两个独立的函数
def func1():
print('咖啡苦不如命苦')
def func2():
print('天天开心')
return func1
func2() # 调用func2
res = func2() # 将func2的返回值赋值给res
res() # 调用res 则是调用func1
——————————运行结果——————————
天天开心
天天开心
咖啡苦不如命苦
2)嵌套的函数
def func1():
print('咖啡苦不如命苦')
def func2():
print('天天开心')
return func2
func1() # 调用func1
res = func1() # 将func1的返回值赋值给res
res() # 调用res 则是调用func2
——————————运行结果——————————
咖啡苦不如命苦
咖啡苦不如命苦
天天开心
-
4可以当容器类型的数据
可以作为 元组、字典、列表、集合的元素,通过索引它们的值加括号调用该函数
def func1():
print('咖啡苦不如命苦')
d1 = {'name':func1}
d1.get('name')() # 咖啡苦不如命苦
5.闭包函数
-
什么是闭包函数
闭包函数的要求
1 该函数定义在另一个函数内部
2 用到了外部函数的局部名称空间中变量
# 简单的闭包函数
def outer():
name = 'duo'
def inner():
print(name)
-
应用1闭包函数是另一种传参方式
传参的方式 1:在定义函数时直接添加形参
传参的方式 2:闭包函数
def outer(name): # 2 可以通过再包一层函数,将该数据传给name
def inner():
print(name) # 1 内层函数inner需要一个变量名name
-
应用2调用传参一次 反复使用
可以将实参的返回值赋值给变量名,然后可以重复调用
def outer(name):
def inner():
print(name)def outer(name):
def inner():
print(name)
return inner
res = outer('duo')
res() # duo
res()
res = outer('kuku')
res() # kuku
res()
三、名称空间
1.名称空间的分类
名称空间:就是在内存内申请一块地方保存变量名和数据值的绑定关系,后续可以通过该变量名来访问数据值,保存变量名的地方叫做名称空间
1.内置名称空间:python解释器中内置的名称的空间
# len print
2.全局名称空间:运行python中文件产生的空间
# 函数名 类名 模块名 变量名
3.局部名称空间:运行函数体代码或者类体代码时产生的空间
# 函数运行时产生的空间
2.名称空间存活周期及作用域
1.内置名称空间:
python解释器启动则创建,关闭则销毁,解释器级别的全局有效
2.全局名称空间:
py文件创建执行后,关闭文件则销毁,文件全局有效
3.局部名称空间:
函数体代码运行则创建,运行结束则销毁,在函数体代码内有效
3.名字的查找顺序
# 大前提 : 首先要弄清现在哪个空间中
1 名字空间的加载顺序: 内置> 全局> 局部
2 名字空间的查找顺序: 局部> 全局> 内置
四、global 和 nonlocal
1.global 在局部名称空间中,使用 global关键字可以修改全局名称空间中该变量名绑定的数据(整型 字典 元组)
2.nonlocal 在内层名称空间中修改层名称空间中的变量名
五、装饰器
1.什么是装饰器
1.装饰器的功能
可以在不改变被装饰对象的代码和调用方式的情况下,为被装饰对象添加新的功能
2.装饰器本质: 是函数参数、闭包函数、函数名多种用法、空间名称组合在一起的产物
2.装饰器模版
1 # 无参装饰器
def outer(func):
def inner(*args, **kwargs):
# 调用函数前可以添加的操作
res = func(*args, **kwargs)
# 调用函数之后可以添加的操作
return res
return inner
2 # 有参装饰器
def wrapper(condition):
def outer(func):
def inner(*args,**kwargs):
# 装饰前的操作
res = func(*args,**kwargs)
# 装饰后的操作
return res
return inner
return outer
3.装饰器语法糖
1.语法糖:用@符号 + 装饰器名 调用该装饰器
2.语法糖作用: 然后把紧贴它下面的函数名当作参数传入装饰器中,然后将返回的值赋值给原函数名
# 举例
def func1():
print('这里是func1')
# 无参装饰器
def outer(func):
def inner(*args, **kwargs):
# 调用函数前可以添加的操作
res = func(*args, **kwargs)
# 调用函数之后可以添加的操作
return res
return inner
1)使用装饰器的方法 1:赋值给原函数名
func1 = outer(func1) # 用原函数名接收被装饰器装饰之后的函数
func1() # 调用方式和函数名称都没改变
2)使用装饰器的方法 2: 使用语法糖,在被装饰的函数前
@outer
def func2():
print('这里是func2')
func2()
4.多层语法糖
多层语法糖的装饰顺序,从下往上,遇到最后一个语法糖才会将与原函数名相同的变量名传给装饰器调用
# 即 函数名 = 最上层装饰器名(第二层装饰器内函数名)
# 且要牢记,在多层语法糖中 函数加括号即函数调用的优先级最高
# 三层语法糖
def outer1(func): # func = wrapper2
print('outer1')
def wrapper1(*args, **kwargs):
print('wrapper1')
res = func(*args, **kwargs)
return res
return wrapper1
def outer2(func): # func = wrapper3
print('outer2')
def wrapper2(*args, **kwargs):
print('wrapper2')
res = func(*args, **kwargs)
return res
return wrapper2
def outer3(func): # func = index
print('outer3')
def wrapper3(*args, **kwargs):
print('wrapper3')
res = func(*args, **kwargs)
return res
return wrapper3
@outer1
@outer2
@outer3
def index():
print('index')
index() # 调用后 先返回 wrapper1 在返回 wrapper2 再返回 wrapper3
六、函数的递归调用
1.什么是函数的递归调用
# 递推:一层层往下
# 回溯:基于明确的结果一层层往上
函数的递归调用分为直接调用和间接调用
1.直接调用:函数在定义阶段中就调用了自己
2.间接调用:函数在定义阶段中调用了别的函数
3.最大递归深度: 1000次,在python中 递归调用是有次数限制的为1000,超过1000次会报错
2.递归函数的定义
递归定义: 1)直接或者间接调用了自己本身 2)每次调用都必须比上次简单,而且有明确的结束条件的函数
3.递归函数的特点
1.直接或者间接的调用了自己,但是递归的效率不高
2.相邻两次的递归之间关系紧密,且上一次递归要为下一次递归作准备
3.每次进入更深一层的递归时,问题本身的复杂程度或者规模会减少
4.必须有一个明确的结束条件
七、算法简介及二分法
1.算法
算法就是针对专门问题的解决方法,算法可以被优化,但是对一个问题来说没有最完美的算法
2.二分法
就是将一段有序数列,不断的一分为二,然后拿中间的值去比较目标数据,然后判断中间值左右两边的小数列哪个更接近目标数据,再去一分为二,直到得到目标数据,或者数列被分割结束。
#举例
l1 = [11, 33, 44, 53, 65, 76, 88, 99, 112, 232, 343]
def get_num(l, target_num):
if len(l) == 0:
print('结束')
middle_index = len(l) // 2
if target_num > l[middle_index]:
right_l = l[middle_index + 1:]
print(right_l)
return get_num(right_l, target_num)
elif target_num < l[middle_index]:
left_l = l[:middle_index]
print(left_l)
return get_num(left_l, target_num)
else:
print('find it')
get_num(l1, 99)
八、生成式
生成式可以对数据集进行相同的操作,从而简化代码
1.列表生成式
l = [变量名 + 想进行的操作 for 元素 in 原列表 if 变量名满足的条件]
# 即在原列表中循环取得元素,如果这个元素满足某个条件,则将其进行操作并加入新列表中,否则去除该数据
l1 = [11, 33, 44, 53, 65, 76, 88, 99, 112, 232, 343]
l2 = [number + 1 for number in l1 if number > 70]
print(l2) # [77, 89, 100, 113, 233, 344]
2.字典生成式
d2 = {i: j for i, j in enumerate('hello', 22)}
print(d2) # {22: 'h', 23: 'e', 24: 'l', 25: 'l', 26: 'o'}
# 生成一个字典,其键值对的配对是 enumerate关键字生成的元组中的元素
d1 = [(11,22)]
d2 = {i: j for i, j in d1}
print(d2)
3.集合生成式
s1 = {i for i in 数据集}
生成一个集合,元素来源于数据集中
s1 = {i for i in 'hello'}
d1 = [11,22,(111,222)]
s1 = {i for i in d1}
print(s1) # {(111, 222), 11, 22}
九、匿名函数
1.语法结构
lambda 形参:返回值
2.特点:匿名函数需要配合其他函数一起使用,且匿名函数不用写 return,其参数可以有多个
十、重要的内置函数
函数名 | 功能 |
---|---|
map 映射 | 根据提供的函数对指定数据集做映射 |
max\min | 返回最大\最小值 |
ruduce | 传多个值,返回一个值 |
isinstance | 判断某个数据是否是某个数据类型 |
zip 组合 | 将列表中位置顺序相同的一起结合成元组 |
filter 过滤 | 过滤数据集中的不符合某条件的数据 |
sorted | 数据集中的数据, 按照大小升序排列 |
十一、常见的内置函数
函数名 | 功能 |
---|---|
abs()绝对值 | 取数据的绝对值 |
all() | 所有数据值对应的布尔值为 True结果才是 True,否则返回 False |
any() | 所有数据值对应的布尔值有一个为 True结果才是 True,否则返回 False |
bin二进制 oct十进制 hex十六进制 int整数 | 将其他进制数转为该进制数 |
bytes() 编码 | 返回一个新的“bytes”对象,它是0<=x<256范围内的不可变整数序列。 |
callable() 调用 | 判断某一个名字是否可以加括号()调用 |
chr() | chr(ASCII码编号) 返回对应字母 |
ord() | ord(对应字母) 返回ASCII码编号 |
dir() | 返回括号内对象里面能调用的 名字 |
divmod() | 返回元组第一个数据为整除数 第二个是余数 |
enmerate(i,起始值) 枚举 | 将i中的元素遍历,并按照顺序和递增的起始值 一一组队输出成一个个元组 |
eval() | eval() 只能识别简单的python代码,具有逻辑性的都不行 |
exec() | 可以识别具有一定逻辑性的python代码 |
id | 返回内存地址 |
input | 获取输入 |
instance | 判断数据类型 |
hash() | 哈希加密 |
open | 由应用程序向操作系统发起系统调用 open(...),操作系统打开该文件,对应一块硬盘空间,并且返回一个文件对象 |
pow(x, y[, z]) | 函数是计算 x 的 y 次方,如果 z 在存在,则再对结果进行取模,其结果等效于 pow(x,y) %z |
range() | 生成一系列连续整数 |
round() 五舍六入 | 把浮点型的数据保留整数 |
sum() | 将数据集中的数据求和 |
十二、可迭代对象
1.可迭代对象的定义
定义:数据对象内置有 __iter__方法,可称为可迭代对象
2.可迭代对象的范围
1.可迭代对象范围(支持for循环)
str list dict tuple set 文件
2.不可迭代对象
int float bool 函数对象
3.可迭代的含义
是否支持for循环,支持for循环的是可迭代对象
# 迭代:更新换代,每次更新换代都得依赖上一次的结果
a ```python
十三、迭代器对象
1.迭代器对象
支持迭代的对象,调用了__iter__方法之后就变成了迭代器对象,其内置了__next__方法
2.迭代器对象
为没有索引的数据类型提供了其他的取值方式
# 也就是说因为又了迭代器对象,字典和集合才能支持 for循环
3.迭代器对象实操
# 案例
s1 = 'hello' # 可迭代对象
res = s1.__iter__() # 调用__iter__方法迭代器对象
print(res.__next__()) # 迭代取值 : for循环本质
一旦__next__取不到值就会报错
4.注意事项
可迭代对象调用__iter__会变成迭代器对象,迭代器对象如果还调用可迭代对象调用__iter__还是迭代器对象没有变化
简写:
iter() # __iter__ 双下iter方法
next() # __next__ 双下next方法
十四、for循环的本质
for 变量名 in 可迭代对象:
循环体代码
本质:
1 先将in后面的数据调用__iter__方法转换为迭代器对象
2 依次用迭代器对象调用__next__取值
3 一旦__next__取不到值报错,for循环会自动捕获并处理
十五、异常捕获与异常处理
1.异常
异常就是代码运行报错,也叫bug
2.异常类型
1)语法错误
不允许出现错误
2)逻辑错误
允许出现,在代码运行之后才可能会出现
3.异常报错显示区的内容
部分 1)异常出现的位置
部分 2)异常出现的类型:部分 3)异常的类型
代码实战篇
1.编写⽤户识别程序
要求:
可循环根据⽤户输⼊的姓名不同输出不同的身份信息
添加程序结束功能(如⽤户输⼊字⺟q直接结束识别程序)
user_info = {'jason': '扫地僧', 'tony': '洗碗⼯', 'kevin': '服务员', 'jack': '配菜员'}
while True:
username = input('请输入您的名字(输入q退出验证):').strip()
if username == 'q':
break
elif username in user_info:
user_info_job = user_info.get(username)
print(f'您的职务为:{user_info_job}')
continue
else:
print('您的职务未识别')
2.利⽤for循环及range⽅法⾃动⽣成链家⼆⼿房多⻚数据⽹址(⼗条以
上即可)
初始⽹址:https://sh.lianjia.com/ershoufang/
# 第2页https://sh.lianjia.com/ershoufang/pg2/
# 第3页https://sh.lianjia.com/ershoufang/pg3/
# 1 首先找到链家网页数据翻页的网址规律
# 2 开始for循环开始获取数据
"""
range(a,b,c)函数是生成从a到 b-1 的数据值,c是这个数列的等差值,不写c默认为1
在python 2.x中,使用range()函数,会将这些数据全部生成,而xrange()则会将这些数据
保存在某处,当我们需要时才会调用
而python 3.x中,已经删除了原来的range()函数,而新版本中的range()则是功能和xrange()一致
"""
# 可以定义一个打印网页的函数
def url_page(a, b, mode=1):
for i in range(a, b, mode):
print('https://sh.lianjia.com/ershoufang/pg%s/' % i)
url_page(1, 20)
3.编写⽤户登录程序
温馨提示:
⽤户名与密码来源于字符串source_data = 'jason|123'
想办法从中拆分出⽤户名和密码⽤于后续账户信息⽐对
普通要求:
1.验证失败情况下可⼀直循环验证 成功则直接退出
拔⾼练习:
1.只允许三次失败机会
2.登录成功后进⼊内层循环,⽤户输⼊任何指令利⽤格式化输出
打印正在执⾏该⽤户指令即可,直到⽤户输⼊字⺟q退出内层循环
source_data = 'jason|123'
count = 1
while True:
# 4 用记录器记录尝试次数
# 6 判断如果尝试三次则无法继续尝试
if count > 3:
print('尝试三次机会已用完')
break
# 1 获取用户名和密码
username = input('请输入用户名:').strip()
password = input('请输入密码:').strip()
# 2 将用户名和密码拆封并 赋值
real_name, real_pwd = source_data.split('|')
# 3 校验用户信息
if username == real_name and password == real_pwd:
print('登陆成功')
# 7 格式化输出输入的指令
while True:
user_func = input('请输入您想要输入的指令(输入q结束):')
if user_func == 'q':
break
else:
print(f'{user_func}正在运行')
else:
# 5 记录器+1
count += 1
print('您的用户名或者密码错误')