关于python:如何替换.txt文件数据库中的dict的特定项

How to replace an specific item of a dict in a .txt file database

我想使用一个.txt文件来存储应用程序的API令牌,但是我一直在试图找到一种方法来替换文件中找到的API密钥/令牌。这是尝试的代码(python 3.5):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
data_to_save = {}
data_to_save['savetime'] = str(datetime.datetime.now())[:19]
data_to_save['api_key'] = key_submitted
data_to_save['user'] = uniqueid
api_exists = False
user_exists = False
with open("databases/api_keys.txt", 'r+') as f:
    database = json.loads(f.read())
    for i in database:
        if i['api_key'] == key_submitted:
            send_text_to_user(userid,"[b]Error: That API key is already in use.[/b]","red")
            api_exists = True
        if i['user'] == uniqueid:
            user_exists = True
    if user_exists == True:
        if api_exists = True:
            send_text_to_user(userid,"[b]Error: Your API key was already saved at another time.[/b]","red")
        else:
            f.write(json.dumps(data_to_save)) #Here, StackOverflow
            send_text_to_user(userid,"[b]Okay, I replaced your API key.[/b]","green")
    f.close()
if user_exists == False:
    writing = open("databases/api_keys.txt", 'a')
    writing.write(json.dumps(data_to_save))
    writing.close()

我还想知道这是最好的方法还是可以优化代码以及如何优化。

谢谢,已经完成了。最终代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
data_to_save = {'savetime': str(datetime.datetime.now())[:19], 'api_key': key_submitted, 'user': uniqueid}
with open("databases/api_keys.txt", 'r') as f:
    database = json.loads(f.read())
    for i in database:
        if i['user'] == uniqueid:
            database.remove(i)
        if i['api_key'] == key_submitted:
            send_text_to_user(userid,"[b]Error: That API key is already in use.[/b]","red")
            api_exists = True
            break
    if not api_exists:
        database.append(data_to_save)
        f.write(json.dumps(database)
    send_text_to_user(userid,"[b]Okay, your API key was succesfully stored.[/b]")

使用这种方法,我们甚至不需要在用户存在或不存在的情况下编写不同的保存,因为如果找到它,它就会将其删除,因此在代码运行时它永远不存在,并且只需要每次保存一个"新"记录,除非API密钥已经属于另一个用户。


给定的代码有很多问题,所以让我们从头开始:

  • 我们不需要创建空的dict对象来填充下一行

    1
    2
    3
    4
    data_to_save = {}
    data_to_save['savetime'] = str(datetime.datetime.now())[:19]
    data_to_save['api_key'] = key_submitted
    data_to_save['user'] = uniqueid

    当我们可以创造它充满

    1
    2
    3
    data_to_save = {'savetime': str(datetime.datetime.now())[:19],
                    'api_key': key_submitted,
                    'user': uniqueid}
  • if语句中不允许赋值(更多见docs)

    1
    if api_exists = True:

    所以这条线会导致SyntaxError(我猜这是一个打字错误)。

  • 支票样

    1
    2
    if user_exists == True:
        ...

    是多余的,我们可以只写

    1
    2
    if user_exists:
        ...

    也有同样的效果。

  • 在使用with语句时,我们不需要显式关闭文件,这是上下文管理器的作用:在退出with语句块后进行清理。

  • 第一次迭代后的databases/api_key.txt文件将具有无效的JSON对象,因为您只是在文件末尾编写新的序列化data_to_save对象,而您应该修改database对象(似乎是一个字典列表)并编写它的序列化新版本,因此我们也不需要r+模式。

  • 让我们定义实用程序函数,它保存新的API密钥数据,例如

    1
    2
    3
    4
    def save_database(database,
                      api_keys_file_path="databases/api_keys.txt"):
        with open(api_keys_file_path, 'w') as api_keys_file:
            api_keys_file.write(json.dumps(database))

    那么我们可以吃点类似的东西

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    data_to_save = {'savetime': str(datetime.datetime.now())[:19],
                    'api_key': key_submitted,
                    'user': uniqueid}
    api_exists = False
    user_exists = False
    with open("databases/api_keys.txt", 'r') as api_keys_file:
        database = json.loads(api_keys_file.read())
        # database object should be iterable,
        # containing dictionaries as elements,
        # so only possible solution -- it is a list of dictionaries
        for i in database:
            if i['api_key'] == key_submitted:
                send_text_to_user(userid,"[b]Error: That API key is already in use.[/b]","red")
                api_exists = True
            if i['user'] == uniqueid:
                user_exists = True

        if user_exists:
            if api_exists:
                send_text_to_user(userid,"[b]Error: Your API key was already saved at another time.[/b]","red")
            else:
                # looking for user record in database
                user_record = next(record for record in database
                                   if record['user'] == uniqueid)
                # setting new API key
                user_record['api_key'] = key_submitted
                save_database(database)
                send_text_to_user(userid,"[b]Okay, I replaced your API key.[/b]","green")

    if not user_exists:
        database.append(data_to_save)
        save_database(database)

    例子

    我用api_keys.txt文件创建了目录databases,其中包含单行

    1
    []

    因为一开始我们没有API密钥。

    假设我们遗漏的对象定义如下

    1
    2
    3
    4
    5
    6
    7
    key_submitted = '699aa2c2f9fc41f880d6ec79a9d55f29'
    uniqueid = 3
    userid = 42


    def send_text_to_user(userid, msg, color):
        print(msg)

    因此,对于上面的代码,它在第一个脚本执行时提供空输出,在第二个脚本执行时提供:

    1
    2
    [b]Error: That API key is already in use.[/b]
    [b]Error: Your API key was already saved at another time.[/b]

    进一步改进

    • 如果满足其中一个条件(api密钥或用户已经在数据库中注册),我们应该从for循环中选择break
    • 也许最好使用已经编写好的数据库,而不是重新设计方向盘?如果你需要JSON物体,你应该看看Tinydb。