【问题标题】:How to build this program without using global variables?如何在不使用全局变量的情况下构建这个程序?
【发布时间】:2020-08-02 06:07:43
【问题描述】:

我刚刚创建了我的第一个 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()

【问题讨论】:

  • 请将此减少并增强为预期的MRE。还要查找避免全局变量的常用方法,并在您的问题中参考您的 remaining 问题。
  • 以一种方式在程序顶部定义这些全局变量,如果您不定义它们它们将运行良好,请使用赋值运算符保存函数的输出,例如 passs = encrpt()
  • 使用全局变量,早就considered harmful了,各种原因不一定只是安全问题。两个主要问题是它使代码更难调试和维护。
  • 避免全局变量的一种非常好的常用方法是遵循 Python 完全支持的 OOP (Object-oriented programming) 范式。

标签: python function variables global


【解决方案1】:

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

【讨论】:

    【解决方案2】:

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

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

    您发布的代码实际上完美地展示了全局变量的症结 - 如果我,您的程序的用户,想要生成多个密码,我得到的结果是意想不到的:

    ['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()
    

    输出:

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

    我还添加了一个入口点main,并更多地利用了标准库。这是切线的,但严格来说,您并没有真正“加密”字符串 - 它更像是混淆,但无论如何。

    【讨论】:

    • 我花了几个小时才花了你 10 分钟。看来我还有很大的成长空间。感谢您提供有用的提示/提示/技巧。非常感谢您花时间和精力将所有内容写出来!
    • @KyleMarvin 每个人都从某个地方开始!很高兴我能帮上忙。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-04-18
    • 1970-01-01
    相关资源
    最近更新 更多