闭包与装饰器
-
-
其实闭包利用了函数嵌套的概念,来看一组闭包的例子
# 看例子之前呢,推荐一个交互式的python命令行,ipython,支持代码提示,行号,自动缩进等等的功能 安装方式: win + r --> cmd --> pip install ipython # 咳咳 来看例子 In [50]: def func1(): ...: x = 1 ...: def func2(): ...: return x ...: return func2 ...:
# 这就是闭包了?是的
闭包的特征:
1 内部函数外部嵌套了函数
2 外函数的返回值是内函数的引用
3 内部函数引用了外函数的临时变量
# 而且返回值变量是私有的In [51]: num1 = func1() In [52]: print(num1.__closure__[0].cell_contents) # 查看闭包的元素 1 In [53]: num2 = func1() In [54]: print(num1()+1,num2()) # 修改了num1,也不会干扰num2 2 1
-
装饰器
-
闭包的另外一种表现形式,主要用于装饰功能,在不改变原代码以及原代码的调用方式,另外的添加额外的功能
-
装饰器分为有参装饰器和无参装饰器两种
-
无参装饰器
# 以下代码在编辑器中实现
import time # 时间模块 def home(): time.sleep(3) # 睡眠3秒 print('this is my home') home() this is my home home函数运行时间为3.003586 # 上面是一个函数,现在为这个函数增加一个计算运行时间的功能 import time def run_time(func): # func == home def wrapper(): # 真正作为装饰的函数 start_time = time.time() # 函数执行前增加的功能 func() # 执行函数(如果被装饰函数需要接收值,次数则需要写为 res = func()) stop_time = time.time() # 函数执行后增加的功能 run = stop_time - start_time print('%s函数运行时间为%f' % (func.__name__,run)) return wrapper # 返回装饰器,闭包的原理 @run_time # 是函数的语法(语法糖), 等同于 home = run_time(home) def home(): # 如果此处需要传参,在上边func也需要写入形参 time.sleep(3) print('this is my home') home() # 没有改变函数的调用方式
-
有参装饰器
# 装饰器需要传参该怎么办?来看
# 实现传入一个int,传入几则函数多运行几秒import time def run_time(my_time): # my_time = def wrapper(func): def inner(name,second): # home start_time = time.time() res = func(name,second+my_time) # home stop_time = time.time() run = stop_time - start_time print('%s函数运行时间为%f' % (func.__name__,run)) return res return inner return wrapper @run_time(2) def home(name,second): time.sleep(second) print('this is %s home' % name) return name print(home('dingh',3)) this is dingh home home函数运行时间为5.000118 dingh
-
装饰器代码实现认证功能
#!/usr/bin/evn python # -*- coding: utf-8 -*- import random import pickle import os # 存放用户信息 user_db = r'user.db' # 登录状态 login_status = {} # 注册用户 def register(db_file): count = 0 while count < 3: # 注册用户密码 reg_user = input('请输出注册用户: ').strip() # 输入空则继续输入 if not reg_user:continue # 输入两次密码 reg_passwd = input('请输入注册密码: ').strip() reg_passwd_repeat = input('请再次输入注册密码: ').strip() # 两次密码一致 if reg_passwd == reg_passwd_repeat: with open(user_db,'rb') as read_f: # 加载用户信息 user_dic = pickle.load(read_f) # 生成用户注册信息 user_dic[reg_user] = reg_passwd # 存入用户注册信息 with open(user_db,'wb') as write_f: pickle.dump(user_dic,write_f) break # 两次密码不一致 else: print('两次密码不一致,请重新注册') count += 1 continue # 认证装饰器 def auth(play): def inner(): # 文件不存在,则创建并写入空字典 if not os.path.exists(user_db): with open(user_db,'wb') as write_f: user_dic = {} pickle.dump(user_dic,write_f) count = 0 while count < 3: land_user = input('用户名: ').strip() if not land_user:continue # 用户已经登录则重新登录其他用户 if land_user in login_status: print('您已经玩过了,下次再来玩吧') continue land_passwd = input('密码: ').strip() with open(user_db,'rb') as read_f: # 加载用户信息 user_dic = pickle.load(read_f) # 如果用户存在 if land_user in user_dic: if user_dic[land_user] == land_passwd: print('登陆成功') login_status[land_user] = 'success' # 玩游戏 point = play() # 返回用户及点数 return land_user,point else: print('密码错误') count += 1 continue else: print('用户不存在,请注册') register(user_db) return inner @auth # 装饰函数 # 玩游戏 def play(): default_point = 0 rule = input('按[1]可以查看规则') if rule == '1': print(''' 规则: 玩家通过任意键进行摇色子,每次摇动为三个色子,结果是三个色子点数的和, 谁摇的点数和加起来最大,谁就是赢家!!! ''') def wave(): # 修改外层函数内的变量 nonlocal default_point count = 0 shake = input('按任意键摇色子,每个玩家只有一次机会哦!') while count < 3: wave_point = random.randint(1,6) # 三个色子点数相加 default_point += wave_point count += 1 # 返回相加的点数 return default_point return wave() while True: # 接收玩家的名称和点数 game_player1,point1 = play() print('您摇的点数是[%s]\n%s' % (point1,'-'*20)) game_player2,point2 = play() print('您摇的点数是[%s]\n%s' % (point2,'-'*20)) print('游戏开始了'.center(30,'-')) print('本局游戏[%s]玩家,投色子点数是%d\n本局游戏[%s]玩家,投色子点数是%d' % \ (game_player1,point1,game_player2,point2)) if point1 > point2: print('[%s]玩家获胜' % game_player1) elif point1 == point2: print('双方平局') else: print('[%s]玩家获胜' % game_player2) inp = input('是否继续游戏?(yes/no)').strip() if not inp:break # 将输入转换为小写 inp = inp.lower() if inp == 'yes': continue elif inp == 'no': break else: break
-
-