一、函数名应用

函数名是什么?函数名是函数的名字,本质:变量,特殊的变量。

函数名(),执行此函数。

python 规范写法

  1. 后面加一个空格,再写内容,就没有波浪线了。

2.一行代码写完,下面一行的的内容要空 2 行,

3.逗号 2 个边的内容要有空格。

如果是不规范的写法,Pycharm 编辑器,会有灰色的波浪线显示。

1.单独打印函数名

  1. def func1():
  2. print(666)
  3. print(func1)

执行输出:

打印的是一个函数内存地址

2.函数名的赋值

  1. def func2():
  2. print(666)
  3. f = func2
  4. print(f())

执行输出:

666

None

3.函数名可以作为容器类数据的元素

下面的函数都要执行

  1. def f1():
  2. print(111)
  3. def f2():
  4. print(222)
  5. def f3():
  6. print(333)
  7. def f4():
  8. print(444)

写 4 个执行代码就可以了

  1. f1()
  2. f2()
  3. f3()
  4. f4()

如果是 100 个呢?

使用 for 循环批量执行函数

  1. def f1():
  2. print(111)
  3. def f2():
  4. print(222)
  5. def f3():
  6. print(333)
  7. def f4():
  8. print(444)
  9. l1 = []
  10. for i in range(1, 5):
  11. l1.append('f' + str(i))
  12. for i in l1:
  13. eval(i)()

执行输出:

111

222

333

444

4.函数名可以作为参数

  1. def f1():
  2. print(666)
  3. def f2(x):
  4. x()
  5. f2(f1)

执行输出:

666

分析如下:

  1. def f1():
  2. print(666)
  3. def f2(x): # x = f1
  4. x() # f1()
  5. f2(f1) #将 f1 函数作为变量传参给 f2,x()表示执行函数 f1(),输出 666

5.函数名可以作为函数的返回值。

  1. def f11(x):
  2. return x #将返回值传给调用者 f11(5),此时 ret = 5
  3. ret = f11(5)
  4. print(ret)

执行输出:

5

  1. def f1():
  2. print(666)
  3. def f2(x):
  4. return x
  5. f2(f1)()

执行输出:

666

代码分析:

  1. def f1():
  2. print(666)
  3. def f2(x): # x = f1
  4. return x #将 f1 返回给函数调用者 f2(f1),此时就相当于 f1 = f2(f1)
  5. f2(f1)() #将 f1 函数作为变量传参给 f2,return 之后 f2(f1)等于 f1,f1()就表示执行 f1 函数,输出 666

f1 是一个特殊变量,加()就可以执行了

第一类对象( first-class object)

1.可在运行期创建

2.可用作函数参数或返回值

3.可存入变量的实体

*不明白?那就记住一句话,就当普通变量用

函数名就是第一类对象

加括号,就可以执行了。

二、闭包

闭包函数:

内部函数包含对外部作用域而非全剧作用域变量的引用,该内部函数称为闭包函数

有如下代码,请补全代码,在函数外部执行 inner()函数

  1. def wrapper():
  2. def inner():
  3. print(666)

第一种写法

  1. def wrapper():
  2. def inner():
  3. print(666)
  4. inner()
  5. wrapper()

执行输出:

666

第二种写法

  1. def wrapper():
  2. def inner():
  3. print(666)
  4. return inner #将 inner 函数返回给调用者 ret,此时 ret = inner
  5. ret = wrapper()
  6. ret() #执行 inner 函数

执行输出:

666

  1. ret = wrapper()
  2. ret()

等同于

  1. wrapper()()

return inner 之后,inner 由临时空间,转换为全局空间了。

因为 ret 赋值了

闭包举例

  1. def wrapper():
  2. name = '老男孩'
  3. def inner():
  4. print(name)
  5. inner()
  6. wrapper()

执行输出:

老男孩

如何判断它是否是一个闭包函数呢? 内层函数名.closure cell 就是=闭包

  1. def wrapper():
  2. name = '老男孩'
  3. def inner():
  4. print(name)
  5. inner()
  6. print(inner.__closure__)
  7. wrapper()

执行输出:

老男孩

(,)

出现了 cell,就表示它是一个闭包函数

  1. name = '老男还'
  2. def wrapper():
  3. def inner():
  4. print(name)
  5. inner()
  6. print(inner.__closure__)
  7. wrapper()

执行输出:

老男还

None

返回值为 None 表示它不是闭包

因为 name 是一个全局变量

如果函数调用了外层变量而非全局变量,那么它就是闭包

  1. name = '老男还'
  2. def wrapper2():
  3. name1 = 'alex'
  4. def inner():
  5. print(name)
  6. print(name1)
  7. inner()
  8. print(inner.__closure__)
  9. wrapper2()

执行输出:

老男还

alex

(,)

只要引用了外层变量至少一次,非全局的,它就是闭包

面试题:

下面的函数,是一个闭包吗?

  1. name = '老男孩'
  2. def wraaper2(n):
  3. # n = '老男孩' 相当于
  4. def inner():
  5. print(n)
  6. inner()
  7. print(inner.__closure__) # None
  8. wraaper2(name)

它也是一个闭包

虽然 wraaper2 传了一个全局变量,但是在函数 wraaper2 内部,inner 引用了外层变量,相当于在函数 inner 外层定义了 n = ‘老男孩’,所以 inner 是一个闭包函数

闭包的好处

当函数开始执行时,如果遇到了闭包,他有一个机制,他会永远开辟一个内存空间,将必包中的变量等值放入其中,不会随着函数的执行完毕而消失。

举一个例子

  1. from urllib.request import urlopen
  2. content = urlopen('http://www.xiaohua100.cn/index.html').read().decode('utf-8')
  3. print(content)

执行输出,是一堆网页源代码。

爬 3 次

  1. from urllib.request import urlopen
  2. content1 = urlopen('http://www.xiaohua100.cn/index.html').read().decode('utf-8')
  3. content2 = urlopen('http://www.xiaohua100.cn/index.html').read().decode('utf-8')
  4. content3 = urlopen('http://www.xiaohua100.cn/index.html').read().decode('utf-8')

内存开了 3 次,很占用内存

把它封装成闭包

  1. from urllib.request import urlopen
  2. def index():
  3. url = "http://www.xiaohua100.cn/index.html"
  4. def get():
  5. return urlopen(url).read()
  6. return get
  7. xiaohua = index()
  8. content = xiaohua()
  9. print(content)

这个例子,只有第一遍,是从网站抓取的。

之后的执行,直接从内存中加载,节省内存空间

三、装饰器初识

装饰器本质上就是一个 python 函数,他可以让其他函数在不需要做任何代码变动的前提下,增加额外的功能,装饰器的返回值也是一个函数对象。

装饰器的应用场景:比如插入日志,性能测试,事务处理,缓存等等场景。

现在我有一个需求,我想让你测试这个函数的执行时间,在不改变这个函数代码的情况下:

先写一个雏形

  1. import time
  2. def func1():
  3. print('in func1')
  4. time.sleep(1) # 模拟程序逻辑
  5. start = time.time()
  6. func1()
  7. print(time.time() - start)

执行输出:

in func1

1.0001070499420166

封装成函数

传一个参数,函数名,就可以查看函数的执行时间了

  1. import time
  2. def func1():
  3. print('in func1')
  4. time.sleep(1) # 模拟程序逻辑
  5. def timmer(f):
  6. start_time = time.time()
  7. f()
  8. end_time = time.time()
  9. print('此函数的执行时间为{}'.format(end_time - start_time))
  10. timmer(func1)

执行输出:

in func1

此函数的执行时间为 1.0002098083496094

原来 100 个函数,都是调用了 func1(),现在测试函数,需要 timeer(func1)。如果想测试所有调用地方的执行时间,那么需要修改 100 个函数位置,改成 timeer(func1),太麻烦了。

不能更改原来的调用方式,同时需要加一个函数执行时间的功能。怎么办呢?

要无限接近于原来的调用方法,慢慢来

先来讲一个变量赋值的例子

  1. a = 1
  2. b = a
  3. a = 2 #a 重新赋值了,原来 a 的值不存在了。但是 b 还是等于原来 a 的值,也就是 1
  4. print(a,b)

执行输出 2,1

  1. ![](https://cdn.nlark.com/yuque/0/2020/png/1484428/1597373707732-aa675e0b-426a-4e25-989d-402a6021409a.png)

1.更改执行方式

  1. import time
  2. def func1():
  3. print('in func1')
  4. time.sleep(1) # 模拟程序逻辑
  5. def timmer(f):
  6. start_time = time.time()
  7. f()
  8. end_time = time.time()
  9. print('此函数的执行时间为{}'.format(end_time - start_time))
  10. f1 = func1 #定义 f1 等于 func1 函数
  11. func1 = timmer #定义 func1 等于 timmer,等式计算右边的。此时 func1 被覆盖了,和原来的没有任何关系,f1 还是等于原来的 func1
  12. func1(f1) #此时相当于执行 timmer(老的 func1)

执行输出:

in func1

此函数的执行时间为 1.0001263618469238

在精简一步

  1. import time
  2. def func1():
  3. print('in func1')
  4. time.sleep(1) # 模拟程序逻辑
  5. def timmer(f): # f = func1
  6. def inner():
  7. start_time = time.time()
  8. f() #执行 func1()
  9. end_time = time.time()
  10. print('此函数的执行时间为{}'.format(end_time - start_time))
  11. return inner #将 inner 函数返回给函数调用者 timmer(func1)
  12. a = timmer(func1) #等式计算右边的,将 func1 函数传给 timmer 函数
  13. a() #此时相当于执行了 inner 函数

执行输出:

in func1

此函数的执行时间为 1.000577449798584

最终版本

  1. import time
  2. def timmer(f): # 2 接收参数.f = func1
  3. def inner():
  4. start_time = time.time() #5.进入 inner 函数
  5. f() #6.执行 f(),也就是原来的 func1 函数。虽然 func1 被覆盖了,但是之前的值还存在。请参考上面 a,b 赋值的例子
  6. end_time = time.time() #10 获取当前时间
  7. print('此函数的执行时间为{}'.format(end_time - start_time)) #11.输出差值
  8. return inner #3.将 inner 函数返回给函数调用者 timmer(func1),此时程序结束,继续执行 func1()
  9. def func1(): #7.进入函数
  10. print('in func1') # 8.打印输出
  11. time.sleep(1) # 9.等待 1 秒
  12. func1 = timmer(func1) #1.等式计算右边的,将 func1 函数传给 timmer 函数,此时 func1 被覆盖了,原来 func1 的不存在了。
  13. func1() #4.这里的 func1 是全新的 func1,就是上面的赋值,此时相当于执行 inner 函数

代码从上至下执行,先加载函数变量 timmer 和 func1。在执行上文说的第 1 步以及后面的,请看数字。

执行输出:

in func1

此函数的执行时间为 1.0009608268737793

但是加这一步,还是不太方便。那么 python 给这种情况,加了一个语法糖@

语法糖指那些没有给计算机语言添加新功能,而只是对人类来说更”甜蜜”的语法

  1. import time
  2. def timmer(f): # f = func1
  3. def inner():
  4. start_time = time.time()
  5. f() #执行 func1()
  6. end_time = time.time()
  7. print('此函数的执行时间为{}'.format(end_time - start_time))
  8. return inner #将 inner 函数返回给函数调用者 timmer(func1)
  9. #语法糖@
  10. @timmer #相当于 func1 = timmer(func1) #这一步就已经覆盖了
  11. def func1():
  12. print('in func1')
  13. time.sleep(1) # 模拟程序逻辑
  14. func1() #相当于执行了 inner()函数

想测试谁,前面加@装饰器函数,即可。

装饰器利用 return 制造了一个假象,func1()执行,其实是执行了 inner()

func1()已经把原来的 func1()给覆盖了

这个装饰器,还不够完整,函数不能传参数

先来举个例子

  1. def func2(a1,b1): #4.执行函数,接收位置参数 a1=1,b1=2
  2. print(a1,b1) #5. 输出 1,2
  3. def func3(a,b): #2. 接收参数,a=1,b=2
  4. func2(a,b) #3. 执行函数 func2(1,2)
  5. func3(1,2) #1.传位置参数 1,2

执行输出:

1 2

func3 执行一遍后,将 a,b 的值,传给 a1,b1 了

上面装饰器的例子,func1,要传 2 个参数 a,b

  1. import time
  2. def timmer(f):
  3. def inner(a,b):
  4. start_time = time.time()
  5. f(a,b)
  6. end_time = time.time()
  7. print('此函数的执行时间为{}'.format(end_time - start_time))
  8. return inner
  9. @timmer
  10. def func1(a,b):
  11. print('in func1 {}{}'.format(a,b))
  12. time.sleep(1) # 模拟程序逻辑
  13. func1(1,2)

执行输出:

in func1 12

此函数的执行时间为 1.0006024837493896

如果有多个参数呢?改成动态参数

  1. import time
  2. def timmer(f):
  3. def inner(*args,**kwargs):
  4. start_time = time.time()
  5. f(*args,**kwargs)
  6. end_time = time.time()
  7. print('此函数的执行时间为{}'.format(end_time - start_time))
  8. return inner
  9. @timmer
  10. def func1(*args,**kwargs):
  11. print('in func1 {}{}'.format(args,kwargs))
  12. time.sleep(1) # 模拟程序逻辑
  13. func1(1,2,a='3',b=4)

执行输出:

in func1 (1, 2){‘b’: 4, ‘a’: ‘3’}

此函数的执行时间为 1.000101089477539

面试题,手写一个装饰器

写装饰器,约定俗成,函数名为 wrapper

第一步

  1. def wrapper(func):
  2. def inner():
  3. func()
  4. return inner

第二步

  1. def wrapper(func):
  2. def inner(*args,**kwargs):
  3. func(*args,**kwargs)
  4. return inner

第三步

  1. def wrapper(func):
  2. def inner(*args,**kwargs):
  3. '''被装饰函数之前'''
  4. ret = func(*args,**kwargs)
  5. '''被装饰函数之后'''
  6. return ret
  7. return inner

完整的

  1. def wrapper(func):
  2. def inner(*args,**kwargs):
  3. '''被装饰函数之前'''
  4. ret = func(*args,**kwargs)
  5. '''被装饰函数之后'''
  6. return ret
  7. return inner
  8. @wrapper
  9. def func(*args,**kwargs):
  10. print(args,kwargs)
  11. return 666
  12. print(func())

作业:

使用函数完成用户登录和注册功能

先让用户选择,是登陆还是注册

选择序号完毕之后,运行相应的程序,

验证成功之后,可以让其继续选择,登陆还是注册,还可以选择退出。

1.先准备函数的雏形

  1. def registered_username(username):
  2. '''
  3. #判断注册用户名是否存在
  4. :param username: 用户名
  5. :return: True 存在 False 不存在
  6. '''
  7. def write_file(username,password):
  8. '''
  9. #写入用户列表文件
  10. :param username: 用户名
  11. :param password: 密码
  12. :return: True 写入成功 False 写入失败
  13. '''
  14. def username_password(username,password):
  15. '''
  16. #判断用户名和密码是否匹配
  17. :param username: 用户名
  18. :param password: 密码
  19. :return: True 匹配成功 False 匹配失败
  20. '''
  21. def register(*args,**kwargs):
  22. '''
  23. 注册逻辑
  24. :return:
  25. '''
  26. pass
  27. def login(*args,**kwargs):
  28. '''
  29. 登录逻辑
  30. :return:
  31. '''
  32. pass
  33. def user_menu(*args,**kwargs):
  34. '''
  35. # 用户菜单
  36. '''
  37. pass

2.先写菜单

  1. def user_menu(*args,**kwargs):
  2. '''
  3. # 用户菜单
  4. '''
  5. # 判断文件是否存在,不存在创建文件
  6. file_exists()
  7. # 循环
  8. while True:
  9. # 打印菜单
  10. menu = ['注册', '登录', '退出']
  11. print('bbs 系统'.center(25, '#'))
  12. for i in range(len(menu)):
  13. print('{}\t{}'.format(i + 1, menu[i]))
  14. print(''.center(27, '#'))
  15. number = input('请选择序号: ').strip()
  16. if number == '1':
  17. # 执行注册程序
  18. register()
  19. elif number == '2':
  20. # 执行登录程序
  21. login()
  22. elif number == '3':
  23. exit()
  24. else:
  25. print('输入错误,请重新输入!')

3.写判断用户列表文件是否存在

  1. def file_exists(*args,**kwargs):
  2. '''
  3. # 判断用户列表文件是否存在
  4. :return: True 存在 False 不存在
  5. '''
  6. # 判断文件是否存在
  7. if os.path.exists(file_name):
  8. return True
  9. else:
  10. with open(file_name, encoding='utf-8', mode='w') as mk:
  11. mk.write('张三 123')
  12. return False

4.再写注册逻辑

  1. def register(*args,**kwargs):
  2. '''
  3. 注册逻辑
  4. :return:
  5. '''
  6. while True:
  7. username = input('请输入注册的用户名,或输入 q 返回菜单:').strip()
  8. if username == '':
  9. print('用户名为空,请重新输入!')
  10. elif username.upper() == 'Q':
  11. break
  12. else:
  13. # 执行判断用户名函数
  14. result = registered_username(username)
  15. if result:
  16. password = input('请输入您的注册的密码:').strip()
  17. # 判断密码
  18. if password == '':
  19. print('密码为空,请重新输入!')
  20. else:
  21. # 执行写入用户列表文件函数
  22. result = write_file(username, password)
  23. if result:
  24. print('注册成功!,您的用户名为: {}\n 倒计时 2 秒返回菜单!'.format(username))
  25. time.sleep(2)
  26. user_menu()
  27. else:
  28. print('注册失败!请重试')
  29. else:
  30. print('用户名已经存在,请重新输入!')

5.判断注册用户名是否可用

  1. def registered_username(username):
  2. '''
  3. #判断注册用户名是否可用
  4. :param username: 用户名
  5. :return: True 可用(用户不存在) False 不可用(用户已存在)
  6. '''
  7. # 纯用户名列表,不包含密码
  8. user_list = []
  9. with open(file_name, encoding='utf-8') as f1:
  10. for i in f1:
  11. # 去空格,以空格切割,转换为列表
  12. li = i.strip().split() # [张三,123]
  13. # 将用户名追加到列表中
  14. user_list.append(li[0])
  15. # 判断用户名是否存在列表中
  16. if username in user_list:
  17. # 返回 False
  18. return False
  19. else:
  20. return True

6.写入用户列表文件

  1. def write_file(username,password):
  2. '''
  3. #写入用户列表文件
  4. :param username: 用户名
  5. :param password: 密码
  6. :return: True 写入成功 False 写入失败
  7. '''
  8. with open(file_name, encoding='utf-8', mode='a') as f2:
  9. f2.write('\n{} {}'.format(username, password))
  10. return True

7.登录逻辑

  1. def login(count=0,max=3):
  2. '''
  3. 登录逻辑
  4. :param count: 初始失败次数
  5. :param max: 最大失败次数
  6. :return:
  7. '''
  8. while count < max:
  9. count += 1
  10. username = input('请输入用户名:').strip()
  11. password = input('请输入密码:').strip()
  12. # 执行验证用户名和密码函数
  13. result = username_password(username,password)
  14. if result:
  15. print('登陆成功\n 倒计时 1 秒返回菜单!')
  16. time.sleep(1)
  17. user_menu()
  18. break
  19. else:
  20. print('用户名或密码错误,还剩余{}次机会!'.format(max - count))
  21. # 返回主菜单
  22. user_menu()

8.判断用户名和密码是否匹配

  1. def username_password(username,password):
  2. '''
  3. #判断用户名和密码是否匹配
  4. :param username: 用户名
  5. :param password: 密码
  6. :return: True 匹配成功 False 匹配失败
  7. '''
  8. # print(username,password)
  9. with open(file_name, encoding='utf-8', mode='r') as f3:
  10. for i in f3:
  11. # print(i)
  12. # 去空格,以空格切割,转换为列表
  13. li = i.strip().split() # [张三,123]
  14. # 判断用户名和密码是否匹配
  15. if username == li[0] and password == li[1]:
  16. result = True
  17. # 当找到匹配时,跳出循环
  18. break
  19. else:
  20. result = False
  21. # 当整个用户列表遍历完成之后,再 return
  22. return result

最终完整代码如下:

  1. # -*- coding: utf-8 -*-
  2. import time,os
  3. #文件名
  4. file_name = 'user_list.txt'
  5. def file_exists(*args,**kwargs):
  6. '''
  7. # 判断用户列表文件是否存在
  8. :return: True 存在 False 不存在
  9. '''
  10. # 判断文件是否存在
  11. if os.path.exists(file_name):
  12. return True
  13. else:
  14. with open(file_name, encoding='utf-8', mode='w') as mk:
  15. mk.write('张三 123')
  16. return False
  17. def registered_username(username):
  18. '''
  19. #判断注册用户名是否可用
  20. :param username: 用户名
  21. :return: True 可用(用户不存在) False 不可用(用户已存在)
  22. '''
  23. # 纯用户名列表,不包含密码
  24. user_list = []
  25. with open(file_name, encoding='utf-8') as f1:
  26. for i in f1:
  27. # 去空格,以空格切割,转换为列表
  28. li = i.strip().split() # [张三,123]
  29. # 将用户名追加到列表中
  30. user_list.append(li[0])
  31. # 判断用户名是否存在列表中
  32. if username in user_list:
  33. # 返回 False
  34. return False
  35. else:
  36. return True
  37. def write_file(username,password):
  38. '''
  39. #写入用户列表文件
  40. :param username: 用户名
  41. :param password: 密码
  42. :return: True 写入成功 False 写入失败
  43. '''
  44. with open(file_name, encoding='utf-8', mode='a') as f2:
  45. f2.write('\n{} {}'.format(username, password))
  46. return True
  47. def username_password(username,password):
  48. '''
  49. #判断用户名和密码是否匹配
  50. :param username: 用户名
  51. :param password: 密码
  52. :return: True 匹配成功 False 匹配失败
  53. '''
  54. # print(username,password)
  55. with open(file_name, encoding='utf-8', mode='r') as f3:
  56. for i in f3:
  57. # print(i)
  58. # 去空格,以空格切割,转换为列表
  59. li = i.strip().split() # [张三,123]
  60. # 判断用户名和密码是否匹配
  61. if username == li[0] and password == li[1]:
  62. result = True
  63. # 当找到匹配时,跳出循环
  64. break
  65. else:
  66. result = False
  67. # 当整个用户列表遍历完成之后,再 return
  68. return result
  69. def register(*args,**kwargs):
  70. '''
  71. 注册逻辑
  72. :return:
  73. '''
  74. while True:
  75. username = input('请输入注册的用户名,或输入 q 返回菜单:').strip()
  76. if username == '':
  77. print('用户名为空,请重新输入!')
  78. elif username.upper() == 'Q':
  79. break
  80. else:
  81. # 执行判断用户名函数
  82. result = registered_username(username)
  83. if result:
  84. password = input('请输入您的注册的密码:').strip()
  85. # 判断密码
  86. if password == '':
  87. print('密码为空,请重新输入!')
  88. else:
  89. # 执行写入用户列表文件函数
  90. result = write_file(username, password)
  91. if result:
  92. print('注册成功!,您的用户名为: {}\n 倒计时 2 秒返回菜单!'.format(username))
  93. time.sleep(2)
  94. user_menu()
  95. else:
  96. print('注册失败!请重试')
  97. else:
  98. print('用户名已经存在,请重新输入!')
  99. def login(count=0,max=3):
  100. '''
  101. 登录逻辑
  102. :param count: 初始失败次数
  103. :param max: 最大失败次数
  104. :return:
  105. '''
  106. while count < max:
  107. count += 1
  108. username = input('请输入用户名:').strip()
  109. password = input('请输入密码:').strip()
  110. # 执行验证用户名和密码函数
  111. result = username_password(username,password)
  112. if result:
  113. print('登陆成功\n 倒计时 1 秒返回菜单!')
  114. time.sleep(1)
  115. user_menu()
  116. break
  117. else:
  118. print('用户名或密码错误,还剩余{}次机会!'.format(max - count))
  119. # 返回主菜单
  120. user_menu()
  121. def user_menu(*args,**kwargs):
  122. '''
  123. # 用户菜单
  124. '''
  125. # 判断文件是否存在,不存在创建文件
  126. file_exists()
  127. # 循环
  128. while True:
  129. # 打印菜单
  130. menu = ['注册', '登录', '退出']
  131. print('bbs 系统'.center(25, '#'))
  132. for i in range(len(menu)):
  133. print('{}\t{}'.format(i + 1, menu[i]))
  134. print(''.center(27, '#'))
  135. number = input('请选择序号: ').strip()
  136. if number == '1':
  137. # 执行注册程序
  138. register()
  139. elif number == '2':
  140. # 执行登录程序
  141. login()
  142. elif number == '3':
  143. exit()
  144. else:
  145. print('输入错误,请重新输入!')
  146. # 执行菜单
  147. user_menu()

执行输出:

  1. ![](https://cdn.nlark.com/yuque/0/2020/png/1484428/1597373707877-15f5404e-8517-425b-a22b-eabd2440c22f.png)