如何在两个函数内部建立全局

时间:2019-01-26 16:13:07

标签: python-3.x

import getpass
from passlib.hash import sha256_crypt

def register():
    username = str(input('username '))
    password = str(getpass.getpass('password ',stream=None))
    exec('global '+username)
    exec(username+'=user('+"'"+username+"'"+','+"'"+password+"'"+')')

def hashPassword(password):
    Passhash = sha256_crypt.hash(password)
    return Passhash

def verifyPassword(password,hashpass):
    return sha256_crypt.verify(password,hashpass)

class user(object):
    users=[]
    def __init__(self, username, password):
        password = str(password)
        if len(password) <= 20:
            self.username = username
            user.users.append(username)
            self.password = hashPassword(password)
        else:
            print("No more than 20 characters in the password")  

def login(username, passsword):
    if username in user.users:
        if verifyPassword(password,exec(username+'.password'))==True:
            print('logged in.')
        else:
            print('wrong password')
    else:
       print('unknown user.')   

由于我对编码还很陌生,所以我试图建立一个基于文本的登录/注册系统。由于某种原因,使用register()函数的某些操作无法正确注册用户,因为当我登录verifypassword()时,它说

if verifyPassword(password,exec(username+'.password'))==True:
  File "<string>", line 1, in <module>
NameError: name 'test' is not defined
>>> 

如果有人可以告诉我发生了什么事。我认为它与全局变量有关,但我不知道如何解决

2 个答案:

答案 0 :(得分:1)

global中的

exec不起作用。

使用globals()[var_name] = var_value在全局范围内设置动态变量名称。

exec通常是 {del} bad idea(如果使用用户提供的输入进行调用)。  它还在功能上(或多或少)具有意外行为,请参见以下示例:

def f():
    exec('a=3')
    print(a)

>>> f()
Traceback [...]
NameError: name 'a' is not defined

(这与在编译时已知局部作用域有关,请参见herehere

此外,您可能会考虑将实际的user对象存储在user.users中-这样可以防止用户选择您在代码中实际使用的名称,并防止意外的行为

编辑:阐述“在编译时已知的本地范围”

由于编译器知道您使用的是什么局部变量,因此可以通过字节码STORE_FASTLOAD_FAST指令进行访问,这些指令在一种数组中进行存储和加载(您可以查看局部变量)通过f.__code__.co_varnames命名),您不仅可以动态添加内容。

为什么这与global有关?

好吧,如上所述,使用了STORE_FASTLOAD_FAST指令(为了速度,您猜对了),以下功能的字节码将是:

>>> def f():
    exec('global x')
    x = 3

>>> dis.dis(f)
  2           0 LOAD_GLOBAL              0 (exec)
              2 LOAD_CONST               1 ('global x')
              4 CALL_FUNCTION            1
              6 POP_TOP

  3           8 LOAD_CONST               2 (3)
             10 STORE_FAST               0 (x)
             12 LOAD_CONST               0 (None)
             14 RETURN_VALUE

第一部分处理呼叫exec。第二部分是作业。无论STORE_FAST刚刚做什么,x都会分配给 local 变量exec

这也是在exec中创建新的局部变量无效的原因:它们没有空间。请注意,这对于exec中设置的局部变量无效,但对于“通常”而言,它们仍然会分配空间。

答案 1 :(得分:0)

在python中,有一个全局变量字典,您可以通过调用globals()来访问它。我不确定exec(...)为何不起作用,但是我会考虑一种不同于将用户存储为变量(由用户名命名)的解决方案。但是要解决您的问题,请保留此设计选择,您可以像这样设置全局用户:globals()[username] = user(username, password),并在登录时执行verifyPassword(password, globals()[username].password)

但是由于全局变量实际上只是字典,因此最好自己维护用户字典。通过选择与另一个全局变量冲突的用户名,用户可能会覆盖全局变量。然后,您还可以消除users类上的静态user列表。可能看起来像这样,其中repository是您与用户的字典:

import hashlib
import base64
import uuid
import getpass
from passlib.hash import sha256_crypt

repository = {}

def register():
    username = str(input('username '))
    password = str(getpass.getpass('password ',stream=None))
    repository[username] = user(username, password)

def hashPassword(password):
    Passhash = sha256_crypt.hash(password)
    return Passhash

def verifyPassword(password,hashpass):
    return sha256_crypt.verify(password,hashpass)

class user(object):
    def __init__(self,username,password):
        password = str(password)
        if len(password) <= 20:
            self.username = username
            self.password = hashPassword(password)
        else:
            print("No more than 20 characters in the password")

def loginUser(username):
    if username == 'exit':
        start()
    if username in repository:
        if loginPass(username)==True:
            print('success')
        else:
            print('passfail')        
    else:
        print('incorrect login USERNAME NOT IN USER.USERS LIST')

def loginPass(username):
    password = getpass.getpass('password ',stream=None)
    if verifyPassword(password, repository[username].password) == True:
        return True
    else:
        return False

def start():
    while 1:
        key1=input('login or register (l/r)')
        if key1=='register':
            del key1
            register()
        elif key1=='r':
            del key1
            register()
        elif key1=='l':
            del key1
            loginUser(input('username or exit to got to l/r screen '))

        else:
            print('ERROR string not reconised among ifs') 

start()