Python中的小表?

时间:2009-09-24 14:07:18

标签: python lookup-tables

假设我没有超过一两个具有不同属性的对象,例如:

UID,名称,价值,颜色,类型,位置

我希望能够使用Location =“Boston”或Type =“Primary”调用所有对象。经典数据库查询类型的东西。

大多数表解决方案(pytables,* sql)对于这么小的一组数据来说真的太过分了。我应该简单地遍历所有对象并为每个数据列创建一个单独的字典(在添加新对象时向字典添加值)?

这会创建像这样的词组:

{'Boston':[234,654,234],'Chicago':[324,765,342]} - 这些3位数的条目代表UID之类的东西。

正如你所看到的,查询这会有点痛苦。

对替代品的任何想法?

3 个答案:

答案 0 :(得分:14)

对于小关系问题,我喜欢使用Python的内置sets

对于location ='Boston'OR type ='Primary'的例子,如果你有这个数据:

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)标准库中。

答案 1 :(得分:5)

我认为sqlite不会“过度” - 它自2.5以来就带有标准的Python,所以不需要安装东西,它可以在内存或本地磁盘文件中制作和处理数据库。真的,怎么会更简单......?如果你想要内存中的所有内容,包括初始值,并希望使用dicts来表达那些初始值,例如......:

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

现在你的内存很小的“db”已准备就绪。当然,在磁盘文件中创建数据库和/或从文本文件,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"')]

等。说真的 - 什么不喜欢?

答案 2 :(得分: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")