在Python中使用多个主键查找列表中的对象

0 投票
3 回答
691 浏览
提问于 2025-04-17 20:18

我有一个包含多个主键的列表:

primary_keys = ['pkey1', 'pkey2', ..., 'pkeyn']

还有一个包含键和值的字典:

kw = {'pkey1': 123, 'pkey2': 456, ..., 'pkeyn': 789, 'other': 'abc', 'values': 'def'}

并且我有一个实例的列表:

instances = [obj, obj, obj]

我想在这个实例列表中找到一个,它的主键和我在 kw 字典中的主键值匹配。

在Python中,有没有简单的方法可以做到这一点?

注意:我很确定我不会有超过两个主键,但我想留出空间以防万一。

3 个回答

0

这里有一段实际可用的代码,还有一个测试:

primary_keys = ['pkey1', 'pkey2', 'pkey3']

kw = {'pkey1': 123, 'pkey2': 456, 'pkey3': 789, 'other': 'abc', 'values': 'def'}

def obj_matches(obj):
    for key in kw.keys():
        if key.startswith('pkey') and getattr(obj, key) == kw[key]:
            return True
    return False

class Foo(object):    
    def __init__(self, pkey1, pkey2, pkey3):
        self.pkey1, self.pkey2, self.pkey3 = pkey1, pkey2, pkey3

instances = [Foo(123, 0, 0), Foo(0, 456, 0), Foo(0, 0, 789), Foo(1, 2, 3)]

matches = []
for obj in instances:
    if obj_matches(obj):
        matches.append(obj)


for m in matches:
    print m.pkey1, m.pkey2, m.pkey3
0

这样做怎么样呢?

match = []
for instance in instances:
    if instance.key in kw:
        match.append(instance)
1

如果有且只有一个符合条件的实例,这样的代码应该能正常工作。

next(inst for inst in instances
          if all(get_key_value(inst, pkey) == kw[pkey] for pkey in primary_keys))

这里的 get_key_value 是一个函数,它会根据给定的实例和键返回对应的值。如果这些键是实例的简单属性,你可以用 getattr 来代替;如果这个实例像个字典一样,你可以用 inst[pkey] 来获取值。

下面是一个简单的使用示例(实例简化为它们的主键集合):

>>> instances = [{'a': 5, 'b': 3}, {'a': 7, 'b': 8},  {'a': -1, 'b': 19}]
>>> primary_keys = ['a', 'b']
>>> kw = {'a': 7, 'b': 8}
>>> next(inst for inst in instances
...           if all(inst[pkey] == kw[pkey] for pkey in primary_keys))
{'a': 7, 'b': 8}

如果没有实例符合这些键,就会抛出一个 StopIteration 的错误,你可以用 try 语句轻松捕获这个错误。如果你想保留所有符合条件的实例,可以把上面的代码改成列表推导式:

[inst for inst in instances
      if all(get_key_value(inst, pkey) == kw[pkey] for pkey in primary_keys)]

撰写回答