在使用装饰器实现登录时,遇到变量作用域的问题。
操作流程:
1、通过视频学习使用装饰器实现登录(基础)
在视频中,要求使用装饰器模拟实现站点登录的流程,如:在访问home方法时通过home方法的配置信息判断需不需要用户登录。如果需要则进行登录流程,让用户输入用户名密码,与文件中已存的用户名密码进行比较,比较成功则标示登录成功,否则不允许访问home方法;当再次访问需要登录的方法page1时,先检查用户是否登录,如果登录则继续方案page1,否则进行登录流程。代码实现如下
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 import os 2 pwd = {} 3 4 logining = False 5 6 with open('./pwd', 'r') as f: 7 for i in f: 8 pwd[i.split('=')[0].strip()] = i.split('=')[1].strip() 9 10 print(pwd) 11 12 13 def login_flag(login_flag): 14 def login(f): 15 def inner(): 16 if(login_flag == "True"): 17 if(logining == False): 18 username = input('username:') 19 password = input('pwd:') 20 if(pwd[username] == password): 21 f() 22 logining = True 23 else: 24 print('username or password is wrong') 25 pass 26 else: 27 f() 28 pass 29 else: 30 f() 31 return inner 32 return login 33 34 35 @login_flag('False') 36 def home(): 37 print("welcome home ") 38 39 @login_flag('True') 40 def page1(): 41 print("welcome page1 ") 42 home() 43 page1()
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 aaaaa = aaaaa 2 bbbbb = bbbbb 3 ccccc = ccccc
但运行时报错
UnboundLocalError: local variable 'logining' referenced before assignment #局部变量“logining”在赋值前被引用
百度后了解到是因为logining变量的作用域问题。
代码中,我们在全局作用域里声明了全局变量logining并赋值为False,那为什么在函数里使用时变成了局部变量呢?
是因为在python中,如果函数中使用了全局变量logining,但是未明确声明它是全局变量,那么python会默认logining是局部变量。所以在函数inner中使用logining时,它是局部变量。但由于在函数里没有给logining赋值就使用了logining所以python报错。
这地方的理解和其他语言会有不一样的地方,在其他语言(如nodejs)中,定义全局变量后,只要在函数中未重新声明变量(使用 var声明),那么该变量就一直是全局变量。(个人理解,之所以会出现这种差异应该是和python中声明变量不用使用关键字的原因。)
找到问题所在之后,又对代码做了修改
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 import os 2 pwd = {} 3 logining = False 4 5 with open('./pwd', 'r') as f: 6 for i in f: 7 pwd[i.split('=')[0].strip()] = i.split('=')[1].strip() 8 9 print(pwd) 10 11 12 def login_flag(login_flag): 13 def login(f): 14 def inner(): 15 if(login_flag == "True"): 16 global logining#--------------- 17 if(logining == False): 18 username = input('username:') 19 password = input('pwd:') 20 if(pwd[username] == password): 21 f() 22 global logining#--------------- 23 logining = True 24 else: 25 print('username or password is wrong') 26 pass 27 else: 28 f() 29 pass 30 else: 31 f() 32 return inner 33 return login 34 35 36 @login_flag('False') 37 def home(): 38 print("welcome home ") 39 40 @login_flag('True') 41 def page1(): 42 print("welcome page1 ") 43 home() 44 page1()
但是运行之后,还是会报错
SyntaxError: name 'logining' is used prior to global declaration#logining在全局声明被使用
这个错误,就不理解了。。。。。
但是当把代码中22行注释后,就可以正常运行了
需求基本完成了,但是代码还有一定的问题。如:使用字典取值时,如果key不存在则会报错,所以需要在取值之前使用 in 判断key是否在字典中。
最终代码如下:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 import os 2 pwd = {} 3 logining = False 4 5 with open('./pwd', 'r') as f: 6 for i in f: 7 pwd[i.split('=')[0].strip()] = i.split('=')[1].strip() 8 9 print(pwd) 10 11 12 def login_flag(login_flag): 13 def login(f): 14 def inner(): 15 global logining #当声明使用的是全局变量时,在该作用域下(inner函数内)的该变量都是全局变量 16 if(login_flag != "True"): 17 return f() 18 if(logining): 19 return f(); 20 username = input('username:') 21 password = input('pwd:') 22 if(username not in pwd): 23 print('username or password is wrong') 24 return 25 if(pwd[username] != password): 26 return print('username or password is wrong') 27 f() 28 logining = True 29 return inner 30 return login 31 32 33 @login_flag('False') 34 def home(): 35 print("welcome home ") 36 37 @login_flag('True') 38 def page1(): 39 print("welcome page1 ") 40 41 42 home() 43 page1()
有错误,请指正。