在使用装饰器实现登录时,遇到变量作用域的问题。

操作流程:

  1、通过视频学习使用装饰器实现登录(基础)

    在视频中,要求使用装饰器模拟实现站点登录的流程,如:在访问home方法时通过home方法的配置信息判断需不需要用户登录。如果需要则进行登录流程,让用户输入用户名密码,与文件中已存的用户名密码进行比较,比较成功则标示登录成功,否则不允许访问home方法;当再次访问需要登录的方法page1时,先检查用户是否登录,如果登录则继续方案page1,否则进行登录流程。代码实现如下

 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()
decorator.py
1 aaaaa = aaaaa
2 bbbbb = bbbbb
3 ccccc = ccccc
pwd

 但运行时报错

UnboundLocalError: local variable 'logining' referenced before assignment #局部变量“logining”在赋值前被引用

百度后了解到是因为logining变量的作用域问题。

代码中,我们在全局作用域里声明了全局变量logining并赋值为False,那为什么在函数里使用时变成了局部变量呢?

是因为在python中,如果函数中使用了全局变量logining,但是未明确声明它是全局变量,那么python会默认logining是局部变量。所以在函数inner中使用logining时,它是局部变量。但由于在函数里没有给logining赋值就使用了logining所以python报错。

这地方的理解和其他语言会有不一样的地方,在其他语言(如nodejs)中,定义全局变量后,只要在函数中未重新声明变量(使用 var声明),那么该变量就一直是全局变量。(个人理解,之所以会出现这种差异应该是和python中声明变量不用使用关键字的原因。)

找到问题所在之后,又对代码做了修改

 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()
decorator2.py

但是运行之后,还是会报错

SyntaxError: name 'logining' is used prior to global declaration#logining在全局声明被使用

这个错误,就不理解了。。。。。

但是当把代码中22行注释后,就可以正常运行了

需求基本完成了,但是代码还有一定的问题。如:使用字典取值时,如果key不存在则会报错,所以需要在取值之前使用 in 判断key是否在字典中。

最终代码如下:

 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()
decorator3.py

有错误,请指正。

posted @ 2017-09-14 16:22  北京雨夜  阅读(527)  评论(0编辑  收藏  举报