如何在不使用全局变量的情况下构建这个程序?

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何在不使用全局变量的情况下构建这个程序?相关的知识,希望对你有一定的参考价值。

我刚刚创建了我的第一个Python项目。我相信有很多可以改进的地方,但我有一个关于如何改变我的代码的具体问题。

我一直在阅读使用全局变量是不明智的 (出于安全考虑)。但我不知道如何使多个函数一起工作(即使用相同的变量),除非它们是全局的。

下面的程序做了三件事。

  1. 生成一个密码
  2. 加密该密码。
  3. 解密密码。

然而,我只在第2部分声明了全局变量来加密密码。

我的问题是:如何改变代码以避免使用全局变量?我把所有的代码都粘贴到下面,供参考,但是全局变量是在 def listToString()def passEncryptor():.

import random

#variables to hold a list and a string
Password = []
Encrypted = ''

#variables to hold the specific characters
#to use in creating the password
a = 'abcdefghijklmnopqrstuvwxyz'
b = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
c = '0123456789'
d = '!@#$%^&*()'

#variable holds all possible values
#that could be found in the password
e = a + b + c + d

#variables will randomize the password length
sm = random.randint(2,3)
lg = random.randint(3,4)

#function generates a randomized password
def passwordGenerator() :

    #append elements from variables a - d
    #to the Password variable
    for x in range(sm) :
        Password.append(random.choice(a))
    for x in range(sm) :
        Password.append(random.choice(b))
    for x in range(lg) :
        Password.append(random.choice(c))
    for x in range(sm) :
        Password.append(random.choice(d))

    #randomize the order of the elements    
    random.shuffle(Password)

    #ensure the first element is a letter
    Password.insert(0, random.choice(a))

    #print to show that the program worked
    print(Password)

#call function to generate a randomized password
passwordGenerator()

#function to store 5 random elements in a string
def listToString() :

    #can't seem to get this to work
    #without using a global variable
    global rand5
    rand5 = ''
    x = random.choices(e, k=5)
    for val in x :
        rand5 += val
    return rand5

#for each element in the password
#add the random 5 elements from listToString()
def passEncryptor():

    global tempPass
    tempPass = ''
    for val in Password :

        #gets 5 new random elements
        listToString()

        #concatenate the random elements
        #with the real password
        tempPass += val + rand5

    print(tempPass)
passEncryptor()

#function to unencrypt an encrypted password
def passDecryptor():

    #convert the encrypted string to a list
    encryptedList = []
    for val in tempPass :
        encryptedList.append(val)

    #remove the random 5 elements    
    decrypt = encryptedList[::6]
    decrypted = ''
    #convert back to a string
    for val in decrypt :
        decrypted += val

    print(decrypted)

passDecryptor()
答案

在这种情况下,它真的只是归结为缺乏知识 - 你没有利用函数参数 - 我假设你不知道那些是什么,因为如果你知道,你会更喜欢它们而不是全局变量。

我不知道 "安全性 "正是你在使用全局变量时牺牲的东西。当然,我可以想到一些假设的例子,我相信有人可以举出一些真实的例子来说明使用全局变量是一个主要的安全问题。我的意思是,使用全局变量并不会使你的程序本质上不安全--只是很容易错误地使用它们(有正确的方法吗?有更好的解决方案可以解决你认为只能用全局变量解决的问题。

你发布的代码实际上完美地展示了全局变量的症结所在--如果我,你的程序的用户,想生成多个密码,得到的结果是出乎意料的。

['d', 'q', '3', 'O', 'g', '1', '$', 'J', '&', '7']
dsLT(mq4N^Yy3(L)%iOr&VM3gTfaZq1&ud9B$RJJ1aJe6Nju&O2*rE7Zz@Y!
dq3Og1$J&7
>>> passwordGenerator()
['n', '&', 'E', ')', '7', '0', '&', 'O', '2', '1', '$', '3', 'q', 'q', 'k', 'J', 'B', '1', 'd', 'g']
>>> passwordGenerator()
['j', '9', 'd', '1', 'k', 'O', 'B', 'q', 'Q', '2', 'g', 'o', 'e', '7', '1', 'n', 'q', '$', 'J', '&', '!', '0', 'A', '!', 'E', ')', '3', '7', '&', '2']
>>> passwordGenerator()
['u', 'o', '!', ')', '0', 'j', 'h', '1', '!', 'q', '7', 'g', '$', '9', 'n', 'k', 'q', '1', '&', 'd', 'J', '2', 'B', '8', '3', '2', '&', '7', 'L', '*', 'O', '5', 'Q', 'e', '&', 'S', '2', 'E', 'A', 'x']
>>> passwordGenerator()
['o', 'h', 'u', '1', 'S', 'q', '&', '7', '$', 'g', '7', '8', '2', '3', 'J', '&', 'k', 'A', '9', 'q', '2', '1', '6', 'B', '0', '*', '&', '!', 'e', 'x', 'j', 'B', 'L', 'a', 'o', '9', ')', '$', 'n', '9', 'U', 's', '!', 'Q', 'E', '2', 'd', '&', '5', 'O']

passwordGenerator 修改了全局变量的状态 Password 通过在每次调用函数时向其追加元素。一般来说,函数是出乎意料地修改了一个变量的状态(这个变量恰好住在函数的范围之外)。这就是为什么全局变量会成为问题的来源,无论是安全还是其他方面。

这是无关紧要的,但你也做了一些不必要的事情,比如洗牌了 Password 随机添加字符后。下面是带函数参数的情况。

def get_random_password(alphabet):
    from random import randint, choices

    password_length = randint(5, 16)
    password = choices(alphabet, k=password_length)

    return "".join(password)


def get_encrypted(alphabet, plaintext):
    from random import choices

    return "".join(char + "".join(choices(alphabet, k=5)) for char in plaintext)

def get_decrypted(encrypted_plaintext):
    return encrypted_plaintext[::6]

def main():
    import string

    alphabet = string.digits + string.ascii_letters + string.punctuation
    # alphabet = string.printable.rstrip()

    password = get_random_password(alphabet)
    encrypted = get_encrypted(alphabet, password)
    decrypted = get_decrypted(encrypted)

    print(f"The password is \"{password}\"")
    print(f"Encrypted: \"{encrypted}\"")
    print(f"Decrypted: \"{decrypted}\"")


if __name__ == "__main__":
    main()

Output:

The password is "O*L7~"
Encrypted: "OiL)V\*I={w&LX5"2-7WF/\+~5%_mP"
Decrypted: "O*L7~"
>>> 

我还添加了一个入口点 main 并更多地利用了标准库的优势。这是个小问题,但严格来说,你并没有真正地 "加密 "字符串--这更像是混淆,但不管怎样。

另一答案

创建一个 阶层 并把你的函数作为类的方法和变量作为这个类的成员。

以上是关于如何在不使用全局变量的情况下构建这个程序?的主要内容,如果未能解决你的问题,请参考以下文章

如何在不使用全局变量的情况下在 bash 中返回一个数组?

如何在不单击的情况下显示片段

如何在不创建新片段的情况下显示片段?

如何在不与 MainActivity 交互的情况下从通知中打开片段页面?

如何在不使用Assembler循环的情况下对3个变量进行排序?

如何在不锁定活动方向的情况下锁定片段方向?