【问题标题】:Pickle module in Python and text filesPython 和文本文件中的 Pickle 模块
【发布时间】:2017-12-28 20:08:12
【问题描述】:

我最近提出了一个问题,并收到了我必须“腌制”我的代码的答案。作为初学者,我不知道该怎么做。

【问题讨论】:

  • 这个for users in users: 看起来......有问题。不应该是for user in users:吗?
  • 你用的是linux吗?如果是这样,请检查您授予 users.txt 文件的权限?也许python无法访问该文件,这就是为什么总是得不到用户的原因。
  • @JulioPérez 我正在使用 IDLE Python 2.7.13
  • @BorrajaX 我已更改但无济于事。不过,感谢您的方法。
  • @BorrajaX 哦,好的。谢谢老哥的解释。现在这对我来说很有意义,因为我正在检查此邮政编码并意识到一切都很好,所以我不再发表评论了哈哈

标签: python text-files pickle


【解决方案1】:

所以,如果我通过查看您提出的与此相关的其他两个问题(12)理解正确,那么您的问题有两个部分:

一个是生成一个包含用户/密码列表的文件,第二个是使用该文件来执行“登录”系统。

写入文件的问题在于您可以将文件视为文本...它并没有真正保留 Python list 的概念,因此您需要弄清楚将您喜欢的 users 列表列表转换为文本,然后返回到 list 列表的方法,以便您可以实际使用它。

有许多预制的序列化格式。这里有一些:JSONCSVYAML,或者在另一个问题中推荐的另一个用户,Pickle

既然你在another post 中提到你将它用于学习目的,那么让我们尽量让它尽可能简单好吗?

让我们将您的练习拆分为两个 python 文件:一个仅生成密码文件,另一个尝试读取并验证用户输入的用户名/密码。

脚本 1:生成密码文件。

所以...您有一个 list 用户名/密码对,您必须将其转换为文本,以便将其存储在文件中。让我们浏览列表中的每个条目并将其写入文件。不妨从 Linux 中汲取一点灵感,在文件的每一行使用分号字符 (;) 来标记用户名和密码之间的分隔符,怎么样?像这样:

sample_users = [
    ["user1", "password1"],
    ["user2", "password2"],
    ["user3", "password3"]
]
users_file = open("./users.txt", "w")
for sample_user in sample_users:
    username = sample_user[0]
    password = sample_user[1]
    users_file.write(username + ';' + password + '\n')
users_file.close()

将其放入.py 文件并运行它。它应该在脚本所在的同一目录中生成一个名为users.txt 的文件。我建议您查看该文件(任何文本编辑器都可以)。你会看到它看起来像这样:

user1;password1
user2;password2
user3;password3

顺便说一句,利用 Python 的 context managers 提供的“自动关闭”功能是一种更好的做法。您可以将该脚本编写为:

with open("./users.txt", "w") as users_file:
    for sample_user in sample_users:
        username = sample_user[0]
        password = sample_user[1]
        users_file.write(username + ';' + password + '\n')

看到了吗?无需致电.close()。如果在运行代码时发生了某些事情,您将确保您的文件在离开 with 块后关闭(当解释器到达 with 块的末尾时,将调用文件的特殊函数 __exit__自动运行,文件将被关闭)


脚本 2:使用密码文件

好的...所以我们在每一行都有一个带有username;password\n 的文件。让我们使用它。

对于这一部分,你需要了解split(使用分号分隔用户名和密码)和rstrip(删除末尾的换行符\n)方法是什么@ 987654350@ 对象做。

我们需要从形状为 username;password\n 的文本行中“重建”两个变量(usernamepassword)。然后查看文件中是否找到了用户名,如果是,提示用户输入密码(并验证是否正确):

def loginFunction():
    userEntry = ""
    foundName = False

    while userEntry == "":
        userEntry = raw_input("Enter your username: ")
        usersFile = open("users.txt", "r")
        for line in usersFile:
            print("This is the line I read:%s", line,)
            # Read line by line instead of loading the whole file into memory
            # In this case, it won't matter, but it's a good practice to avoid
            # running out of memory if you have reaaaally large files
            line_without_newline = line.rstrip('\n')       # Remove ending \n
            user_record = line_without_newline.split(';')  # Separate into username and password (make the line a list again)
            userName = user_record[0]
            password = user_record[1]
            # Might as well do userName, password = line_without_newline.split(';')
            if userName == userEntry:
                foundName = True
                print("User found. Verifying password.")
                passwordEntry = raw_input("Enter your password: ")
                if passwordEntry == password:
                    print "Username and passwords are correct"
                    break
                else:
                    print "incorrect"
                    userEntry = ""

        if not foundName:
            print("Username not recognised")
            userEntry = ""


if __name__ == "__main__":
    loginFunction()

我相信这应该做你想要的?如果您有其他问题,请在答案中发表评论。

玩得开心编码!


PS:那么……泡菜怎么样?

Pickle 是一个以“更安全”和更自动化的方式将 Python 对象序列化为文件的模块。如果你想使用它,下面是方法(至少是一种方式):

  1. 生成密码文件:

    import pickle
    
    sample_users = [
        ["user1", "password1"],
        ["user2", "password2"],
        ["user3", "password3"]
     ]
    
     with open('./users.txt', 'w') as f:
         pickler = pickle.Pickler(f)
         for sample_user in sample_users:
            pickler.dump(sample_user)
    

    和以前一样,此时我建议您使用常规文本编辑器查看文件users.txt 的外观。您会看到它与之前的文件(用户名和密码用分号分隔的文件)完全不同。是这样的:

        (lp0
        S'user1'
        p1
        aS'password1'
        p2
        a.(lp3
        S'user2'
        p4
        aS'password2'
        p5
        a.(lp6
        S'user3'
        p7
        aS'password3'
        p8
        a.%
    
  2. 使用文件:

    import pickle
    
    def loginFunction():
        userEntry = ""
    
        while userEntry == "":
            userEntry = raw_input("Enter your username: ")
            usersFile = open("users.txt", "r")
            unpickler = pickle.Unpickler(usersFile)
            while True:
                try:
                    user_record = unpickler.load()
                    userName = user_record[0]
                    password = user_record[1]
                    if userName == userEntry:
                        print("User found. Verifying password.")
                        passwordEntry = raw_input("Enter your password: ")
                        if passwordEntry == password:
                            print "Username and passwords are correct"
                        else:
                            print "incorrect"
                            userEntry = ""
                        # Watch out for the indentation here!!
                        break  # Break anyway if the username has been found
    
    
                except EOFError:
                    # Oh oh... the call to `unpickler.load` broke 
                    # because we reached the end of the file and
                    # there's nothing else to load...
                    print("Username not recognised")
                    userEntry = ""
                    break
    
    
    if __name__ == "__main__":
        loginFunction()
    

如果您意识到,当您执行 user_record = unpickler.load() 时,您已经在 user_record 变量中获得了 2 项 Python list。您无需将文本转换为列表:unpickler 已经为您完成了这项工作。这要归功于picker.dump 存储在文件中的所有“额外”信息,这使得unpickler 能够“知道”需要返回的对象是一个列表。

【讨论】:

  • 嗨。非常感谢您的回答!它简单明了,易于理解,正是我想要的!但是,我仍然收到“无法识别用户名”。我实际上意识到它根本没有使用您建议的“with”功能写入文件。知道为什么会这样吗?顺便说一句,我喜欢你的回答方式!我可能只需要你辅导我哈哈
  • 嗯...很高兴我帮助了(我喜欢编程,我想我喜欢传播快乐,呵呵) 至于你的问题:with 只是为了“打开”文件对象并控制(或“自动化”,如果可以的话)它的关闭。它并没有真正完成写作。写入是在with 完成的,带有文件写入指令(例如writewritelines...任何这些)。也许你错过了它?此外,缩进(空格)很重要(with 打开一个新的... 块)缩进是否正确?
  • 恭喜!!既然你用它来学习,我建议你放很多 print 语句来查看代码中的“事物”(代码在做什么)玩得开心!
  • 很棒的小费,谢谢!我从中学到了很多。感谢您的帮助!
  • 没问题!顺便说一句,我在我的答案中添加了最后一段(自从我写它以来一直困扰着我的东西)以确保我解释了使用 pickle 的优势(也就是说,基本上,pickle/unpickle 能够知道什么类型对象被保存在文件中)享受! :)
【解决方案2】:

这是使用pickle创建登录系统的方式,但我不推荐这样做,因为存在很多安全问题。我更喜欢将python连接到SQL服务器并将密码存储在数据库中。

import pickle

def register(username,password):
    user_details = dict()
    with open("users.txt",'rb') as f:
        user_details = pickle.load(f)
    if username in user_details:
        print "User already exsits"
    else:
        user_details[username] = password
        print "User added successfully"
    with open("users.txt",'wb+') as f:
        pickle.dump(user_details,f)

def login(username,password):
    user_details = dict()
    with open("users.txt",'rb') as f:
        user_details = pickle.load(f)
    if username in user_details:
        if user_details[username] == password:
            print "Correct Login successful"
        else:
            print "Incorrect Details"

def init():
    user_details = dict()
    with open("users.txt",'wb+') as f:
        pickle.dump(user_details,f)

init()
register("s","s")
login("s","s")

要初始化调用 init() 函数。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-02-28
    • 1970-01-01
    • 1970-01-01
    • 2018-05-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多