gpt4 book ai didi

python - 如何在 python 中设计一个像 sqlite 类的字典,它可以使用不同的字段作为 "key"?

转载 作者:太空宇宙 更新时间:2023-11-04 01:42:33 26 4
gpt4 key购买 nike

我有一个这样的数据结构,

"ID  NAME  BIRTH     AGE    SEX"
=================================
1 Joe 01011980 30 M
2 Rose 12111986 24 F
3 Tom 31121965 35 M
4 Joe 15091990 20 M

我想用 python + sqlite 以简单的方式存储和查询数据。我正在尝试设计一个类似 dict 的对象来存储和检索这些信息,数据库也可以是 与其他应用程序共享 以一种简单的方式。( just a plain database table for other applicationthen the pickle and ySerial like object should not fit for it 。)

例如:
d = mysqlitedict.open('student_table')  
d['1'] = ["Joe","01011980","30","M"]
d['2'] = ["Rose","12111986","24","F"]

这可能是合理的,因为我可以使用 __setitem__()如果将“ID”作为键,其余部分作为该 dict 之类的对象的值,则可以解决这个问题。

问题是,如果我想在语义上使用其他字段作为键,以“NAME”为例:
 d['Joe'] = ["1","01011980","30","M"] 

这将是一个问题,因为像对象这样的字典在语义上应该有一个键/值对,因为现在“ID”是键,“NAME”不能在这里覆盖键。

那么我的问题是,我可以设计我的类(class)然后我可以这样做吗?
 d[key="NAME", "Joe"] = ["1","01011980","30","M"] 
d[key="ID",'1'] = ["Joe","01011980","30","M"]

d.update(key = "ID", {'1':["Joe","01011980","30","M"]})

>>>d[key="NAME", 'Joe']
["1","Joe","01011980","30","M"]
["1","Joe","15091990","20","M"]

>>>d.has_key(key="NAME", 'Joe']
True

我将不胜感激任何答复!

凯里

最佳答案

sqlite是一个 SQL 数据库,在使用时效果最好(包装在 SQLAlchemy 中,或者如果你真的坚持的话;-)。

语法如 d[key="NAME", 'Joe']只是非法的 Python,不管你做了多少包裹、喘气和喘气。一个简单的围绕 DB 连接的类包装器很容易,但它永远不会给你那种语法——比如 d.fetch('Joe', key='Name')相当容易实现,但索引与函数调用的语法非常不同,即使在后者中命名参数也必须在位置参数之后。

如果你愿意放弃你雄心勃勃的语法梦想,转而使用合理的 Python 语法,并且需要帮助设计一个类来实现后者,当然可以随时问(我很快就要 sleep 了,但我当然,其他晚睡者会渴望提供帮助;-)。

编辑 :鉴于 OP 的澄清(在评论中),它看起来像 set_key方法是可以接受的,以保持 Python 可接受的语法(尽管语义当然仍然有点过时,因为 OP 想要一个“类似 dict”的对象,它可能有 非唯一 键——没有这样的东西在 Python 中,真的......但是,我们至少可以近似它)。

所以,这是第一个草图(需要 Python 2.6 或更高版本——只是因为我使用了 collections.MutableMapping 来获取其他类似 dict 的方法和 .format 来格式化字符串;如果你被困在 2.5 中,请使用 %-formatting字符串和 UserDict.DictMixin 将工作):

import collections
import sqlite3

class SqliteDict(collections.MutableMapping):
@classmethod
def create(cls, path, columns):
conn = sqlite3.connect(path)
conn.execute('DROP TABLE IF EXISTS SqliteDict')
conn.execute('CREATE TABLE SqliteDict ({0})'.format(','.join(columns.split())))
conn.commit()
return cls(conn)

@classmethod
def open(cls, path):
conn = sqlite3.connect(path)
return cls(conn)

def __init__(self, conn):
# looks like for sime weird reason you want str, not unicode, when feasible, so...:
conn.text_factory = sqlite3.OptimizedUnicode
c = conn.cursor()
c.execute('SELECT * FROM SqliteDict LIMIT 0')
self.cols = [x[0] for x in c.description]
self.conn = conn
# start with a keyname (==column name) of `ID`
self.set_key('ID')

def set_key(self, key):
self.i = self.cols.index(key)
self.kn = key

def __len__(self):
c = self.conn.cursor()
c.execute('SELECT COUNT(*) FROM SqliteDict')
return c.fetchone()[0]

def __iter__(self):
c = self.conn.cursor()
c.execute('SELECT * FROM SqliteDict')
while True:
result = c.fetchone()
if result is None: break
k = result.pop(self.i)
return k, result

def __getitem__(self, k):
c = self.conn.cursor()
# print 'doing:', 'SELECT * FROM SqliteDict WHERE {0}=?'.format(self.kn)
# print ' with:', repr(k)
c.execute('SELECT * FROM SqliteDict WHERE {0}=?'.format(self.kn), (k,))
result = [list(r) for r in c.fetchall()]
# print ' resu:', repr(result)
for r in result: del r[self.i]
return result

def __contains__(self, k):
c = self.conn.cursor()
c.execute('SELECT * FROM SqliteDict WHERE {0}=?'.format(self.kn), (k,))
return c.fetchone() is not None

def __delitem__(self, k):
c = self.conn.cursor()
c.execute('DELETE FROM SqliteDict WHERE {0}=?'.format(self.kn), (k,))
self.conn.commit()

def __setitem__(self, k, v):
r = list(v)
r.insert(self.i, k)
if len(r) != len(self.cols):
raise ValueError, 'len({0}) is {1}, must be {2} instead'.format(r, len(r), len(self.cols))
c = self.conn.cursor()
# print 'doing:', 'REPLACE INTO SqliteDict VALUES({0})'.format(','.join(['?']*len(r)))
# print ' with:', r
c.execute('REPLACE INTO SqliteDict VALUES({0})'.format(','.join(['?']*len(r))), r)
self.conn.commit()

def close(self):
self.conn.close()


def main():
d = SqliteDict.create('student_table', 'ID NAME BIRTH AGE SEX')
d['1'] = ["Joe", "01011980", "30", "M"]
d['2'] = ["Rose", "12111986", "24", "F"]
print len(d), 'items in table created.'
print d['2']
print d['1']
d.close()

d = SqliteDict.open('student_table')
d.set_key('NAME')
print len(d), 'items in table opened.'
print d['Joe']


if __name__ == '__main__':
main()

该类不打算直接实例化(尽管可以通过将打开的 sqlite3 连接传递到具有适当 SqliteDict 表的数据库来实现),而是通过两个类方法 create (创建新数据库或清除现有数据库)和 open ,这似乎比替代方案更符合 OP 的需求(让 __init__ 采用 DB 文件路径和一个描述如何打开它的选项字符串,就像 gdbm 等模块采用 -- 'r' 来打开读取-仅, 'c' 创建或清除, 'w' 打开读写——当然很容易调整)。在传递(作为空格分隔的字符串)到 create 的列中,那里 必须成为一名 ID (对于构建和使用此类的实例时可能发生的众多用户错误中的任何一个,我并没有特别注意提出“正确的”错误;错误将发生在所有不正确的使用中,但不一定是显而易见的错误用户)。

一旦一个实例被打开(或创建),它的行为就尽可能接近一个字典,除了所有设置的值必须是长度完全正确的列表,而返回的值是列表的列表(由于奇怪的“非-唯一键”问题)。比如上面的代码,运行时,打印
2 items in table created.
[['Rose', '12111986', '24', 'F']]
[['Joe', '01011980', '30', 'M']]
2 items in table opened.
[['1', '01011980', '30', 'M']]

“Pythonically 荒谬”的行为是 d[x] = d[x] 失败——因为右手边是一个列表,例如带有单个项目(这是列值的列表),而项目分配绝对需要一个列表,例如四个项目(列值)。这种荒谬在 OP 请求的语义中,并且只能通过再次彻底改变这种荒谬的所需语义来改变(例如,强制项目分配在 RHS 上有一个列表列表,并使用 executemany 代替普通的 execute )。

键的非唯一性也使得无法猜测 d[x] = v , 用于 key k对应于某个数字 n表条目,旨在替换一个(如果是这样, 其中 一个?!)或所有这些条目,或者添加另一个新条目。在上面的代码中,我采用了“添加另一个条目”的解释,但使用了 SQL 语句 REPLACE那,应该 CREATE TABLE更改为指定某些唯一性约束,如果否则将违反唯一性约束,则会将某些语义从“添加条目”更改为“替换条目”。

我会让大家玩这个代码,并反射(reflect) Python 映射和关系表之间的语义差距有多大,OP 迫切希望弥合这一点(显然是他渴望“使用更好的语法”的副作用)比 SQL 提供的还多——我想知道他 是否有 按照我的建议查看 SqlAlchemy)。

我想,最后,重要的教训是我在开头所说的,在我昨天写的部分答案的第一段中,我自述......:

sqlite is a SQL database and works by far best when used as such (wrapped in SQLAlchemy or whatever if you really insist;-).

关于python - 如何在 python 中设计一个像 sqlite 类的字典,它可以使用不同的字段作为 "key"?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3464787/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com