Python 使用多个字典组织数据

3 投票
4 回答
1625 浏览
提问于 2025-04-15 15:55

我正在尝试创建一个小型的服务器应用程序,想问一下关于用字典(dict)来组织数据的问题。目前,我是通过连接的套接字来分组数据(主要是为了验证数据来源和发送数据)。像这样:connected[socket] = account_data。基本上,每个连接的人都会有他们的账户数据。因为某些字段,比如账户ID,会经常用来比较和检查信息,所以我想用另一个字典来加快速度。

举个例子:如果我想用上面的方法找到一个账户ID,我就得用一个循环去遍历所有的连接,查看每个连接的账户数据中的账户ID,然后进行比较。这种方法似乎比较慢。如果我能创建一个字典,把账户ID作为键,我觉得这样可以稍微加快一些。问题是,我计划使用三个不同的字典,它们的排序方式都不一样。有些数据可能会频繁变化,更新每一个字典似乎会很麻烦;有没有办法把它们链接在一起呢?

也许我可以更简单地解释一下我的问题: 你有字典A、字典B、字典C,还有一些数据。字典A、B和C都包含相同的数据。我希望如果数据发生变化,字典A、B和C中的数据也都能跟着变化。当然,我可以一直用字典A = 数据,字典B = 数据,等等,但这样写久了代码会变得很重复。我知道字典创建后数据就固定了,所以我不太确定有没有解决办法。我只是想找一些建议,看看在这种情况下最好的数据组织方式是什么。

4 个回答

1

你可以这样做:

connected[socket] = accountids[account_data.accountid] = account_data

假设 account_data 是一个可以改变的对象,并且它有一些属性,这样在两个字典中就会用不同的键来引用同一个对象。其实不一定要写成一行,也就是说:

connected[socket] = account_data
accountids[account_data.accountid] = account_data

在同一行中进行多个赋值只是为了方便;真正让它按你想要的方式工作的原因是,Python 在赋值、传递参数、返回语句等操作中,都是通过“对象引用”来处理的。

2

首先,数据不需要重复存储。你可以有三个字典,每个字典用不同的键,但它们的值可以指向同一个对象。

这样做的话,你只需要修改一次这个值对象,所有的字典都会自动更新(更准确地说,因为字典只存储了一个引用,所以它们会保持最新状态)。

接下来,你需要确保“引用完整性”,也就是说,如果某条记录被删除了,三个字典中对应的条目也要被删除。如果记录被修改了,那么那些键已经改变的字典也需要把旧记录删除,然后再用新键重新添加。这可以通过一个类来实现,这个类包含所有三个字典,并且有添加(Add())、删除(Remove())和(如果需要的话)更新(Update())的方法。

0

如果你有字典的引用,更新字典的内容会在所有引用它的地方显示出来。

比如,一个客户连接上来并保持一个套接字,叫做 sock。你加载他的账户信息,并把它放到 connections[sock] 里。然后,你还保持一个账户ID的字典(反向查找),里面有指向账户的引用,叫做 accounts[account_id]。我们来试试这个...

connected = {}
accounts = {}

def load_account(acct):
    return db_magic(acct)                             # Grab a dictionary from the DB

def somebody_connected(sck, acct):
    global connected, accounts
    account = load_account(acct)
    connected[sck] = account                          # Now we have it by socket
    accounts[acct["accountid"]] = account             # Now we have it by account ID

因为我们把 account 赋值给了两个不同的地方,所以对这个字典的任何修改(无论在哪个结构里)都会在另一个地方反映出来。那么...

def update_username(acct_id, new_username):
    accounts[acct_id]["username"] = new_username

def what_is_my_username(sck):
    sck.send(connected[sck]["username"])              # In response to GIMME_USERNAME

我们在 update_username 中做的更改,会在执行 sck.send 时自动被识别,因为引用是完全一样的。

撰写回答