Python中的小表格?

13 投票
3 回答
14345 浏览
提问于 2025-04-15 14:34

假设我手上有一两打不同属性的对象,比如说:

UID、名称、值、颜色、类型、位置

我想能方便地找到所有位置是“波士顿”的对象,或者类型是“主要”的对象。这就像在数据库里查询数据一样。

不过,大多数表格解决方案(比如pytables或者SQL)对于这么少的数据来说实在是太复杂了。我是不是可以简单地遍历所有对象,然后为每一列数据创建一个单独的字典(在添加新对象时把值加到字典里)呢?

这样的话,就会生成像这样的字典:

{'波士顿' : [234, 654, 234], '芝加哥' : [324, 765, 342]} - 这里面的三位数字代表像UID这样的东西。

如你所见,查询这些数据会有点麻烦。

有没有什么其他的好主意呢?

3 个回答

2

如果数据量真的很小,我就不想费心去建立索引,可能只会写一个辅助函数:

users = [
   dict(Name="Mr. Foo", Location="Boston", Type="Secondary"),
   dict(Name="Mr. Bar", Location="New York", Type="Primary"),
   dict(Name="Mr. Quux", Location="Chicago", Type="Secondary"),
   ]

def search(dictlist, **kwargs):
   def match(d):
      for k,v in kwargs.iteritems():
         try: 
            if d[k] != v: 
               return False
         except KeyError:
            return False
      return True

   return [d for d in dictlist if match(d)] 

这样就可以写出看起来很不错的查询语句,比如:

result = search(users, Type="Secondary")
6

我觉得使用sqlite并不会太复杂,因为它从Python 2.5开始就自带了,所以你不需要额外安装什么。它可以在内存中或者本地磁盘文件中创建和管理数据库。其实,怎么会更简单呢...? 如果你想把所有数据都放在内存里,包括初始值,并且想用字典来表示这些初始值,比如说...:

import sqlite3

db = sqlite3.connect(':memory:')
db.execute('Create table Users (Name, Location, Type)')
db.executemany('Insert into Users values(:Name, :Location, :Type)', [
   dict(Name="Mr. Foo", Location="Boston", Type="Secondary"),
   dict(Name="Mr. Bar", Location="New York", Type="Primary"),
   dict(Name="Mr. Quux", Location="Chicago", Type="Secondary"),
   ])
db.commit()
db.row_factory = sqlite3.Row

这样你的内存中的小“数据库”就准备好了。其实在磁盘文件中创建数据库,或者从文本文件、CSV文件等读取初始值,也并不难。

查询方面特别灵活、简单又方便,比如你可以随意混合字符串插入和参数替换...:

def where(w, *a):
  c = db.cursor()
  c.execute('Select * From Users where %s' % w, *a)
  return c.fetchall()

print [r["Name"] for r in where('Type="Secondary"')]

输出的结果是 [u'Mr. Foo', u'Mr. Quux'],这和更优雅但等效的方式是一样的。

print [r["Name"] for r in where('Type=?', ["Secondary"])]

而你想要的查询就是:

print [r["Name"] for r in where('Location="Boston" or Type="Primary"')]

等等。说真的,哪里不好呢?

14

对于一些小型的关系型问题,我很喜欢使用Python自带的集合

比如说,如果你想查找位置是'波士顿'或者类型是'主要'的数据,假设你有这样的数据:

users = {
   1: dict(Name="Mr. Foo", Location="Boston", Type="Secondary"),
   2: dict(Name="Mr. Bar", Location="New York", Type="Primary"),
   3: dict(Name="Mr. Quux", Location="Chicago", Type="Secondary"),
   #...
}

你可以这样写WHERE ... OR ...的查询:

set1 = set(u for u in users if users[u]['Location'] == 'Boston')
set2 = set(u for u in users if users[u]['Type'] == 'Primary')
result = set1.union(set2)

或者只用一个表达式来实现:

result = set(u for u in users if users[u]['Location'] == 'Boston'
                              or users[u]['Type'] == 'Primary')

你还可以利用itertools里的函数来高效地查询数据。例如,如果你想做类似于GROUP BY city的操作:

cities = ('Boston', 'New York', 'Chicago')
cities_users = dict(map(lambda city: (city, ifilter(lambda u: users[u]['Location'] == city, users)), cities))

你也可以手动建立索引(比如建立一个dict,把位置映射到用户ID)来加快查询速度。如果这样做还是太慢或者太麻烦,那我可能会转向使用sqlite,这在Python(2.5)标准库中已经包含了。

撰写回答