Python字典检查是否存在除给定键之外的任何键

5
假设我有一个为包裹指定某些属性的字典:
d = {'from': 'Bob', 'to': 'Joe', 'item': 'book', 'weight': '3.5lbs'}
为了检查包裹字典的有效性,它需要具有“from”和“to”键,并且可以有任意数量的属性,但必须至少有一个属性。 因此,字典可以具有“项目”或“重量”,两者都可以,但不能都没有。 属性键可以是任何内容,不局限于“项”或“重量”。
那么,如何检查字典以确保它们有效,即具有“to”、“from”和至少另一个键?
我唯一想到的方法是获取 d.keys(),删除“from”和“to”键,并检查它是否为空。
有更好的方法吗?

你可以尝试这样写 - 如果 len(d.keys()) > 2 并且 'from' 和 'to' 在 d.keys() 中: - Tanveer Alam
那么我不知道在这种情况下字典是否是理想的数据结构。 - Dylan Madisetti
你会建议什么样的更理想的数据结构呢?谢谢。 - Vaibhav Aggarwal
1
也许可以创建一个类来为这些捆绑包创建对象。你的构造函数可以强制设置 tofrom 属性,并要求设置一个额外的属性。 - Dylan Madisetti
4个回答

11
must = {"from", "to"}
print len(d) > len(must) and all(key in d for key in must)
# True
这个解决方案确保您的字典元素数量大于must集合中的元素,并且must集合中的所有元素都将出现在该字典中。
此解决方案的优点是易于扩展。如果您想要确保字典中存在另一个参数,只需将其包含在must字典中,它就可以正常工作。您不必更改逻辑。 编辑 除此之外,如果您使用的是Python 2.7,可以更简洁地这样写:
print d.viewkeys() > {"from", "to"}

如果你正在使用Python 3.x,你可以直接这样写:

print(d.keys() > {"from", "to"})

这个技巧之所以有效,是因为d.viewkeysd.keys返回类似于集合的对象,因此我们可以使用集合比较运算符。 >用于检查左侧集合是否是严格超集的右侧集合。为了满足条件,左侧类似于集合的对象应该同时具有fromto,以及某些其他对象。

引用自set.issuperset文档,

set > other

测试集合是否是其他的真超集,即set >= other and set != other


谢谢,但正如我所说的那样,可选键可以是任何东西,不仅限于项目或重量。 - Vaibhav Aggarwal
@Veedrac 嗯,我也添加了一个备选方案,看起来可以吗? :) - thefourtheye
1
为什么不直接使用 {"from", "to"} < set(d) 呢?避免使用 set 的原因是因为它的时间复杂度是 O(n),而不是因为它难看。 - Veedrac
@Veedrac 哦,那看起来更好了。谢谢 :) 已经包含在答案中了。但是,除了 d.viewkeys() | {} 之外,其他使用 set 的都会是 O(N) 吧。 - thefourtheye
1
@Veedrac 好的,这很奇怪。请检查更新后的答案。这不需要进行“set”转换。 - thefourtheye
显示剩余6条评论

1
使用以下代码:

def exists(var, dict):
    try:
        x = dict[var]
        return True
    except KeyError:
        return False

def check(dict):
    if exists('from', dict) == False:
        return False
    if exists('to', dict) == False:
        return False
    if exists('item', dict) == False and exists('weight', dict) == False:
        return False
    return True

def main():
    d = {'from': 'Bob', 'to': 'Joe', 'item': 'book', 'weight': '3.5lbs'}
    mybool = check(d)
    print mybool

if __name__ == '__main__':
    main()

谢谢,但我觉得这有点过头了。感激不尽! - Vaibhav Aggarwal

1
这并没有解决OP的问题,但是提供了我认为更好的实践解决方案。我意识到已经有答案了,但是我花了几分钟时间研究最佳实践,所以想分享一下。
使用字典的问题:
- 字典是基于键值的。由于“to”和“from”是必须的,而“item”和“weight”是可选的,因此你本质上有两种不同类型的键值。 - 字典应该是无逻辑的。通过设置某些要求,你违反了字典的原则,它只是用来保存数据的。为了创建一个实例,你需要构建某种逻辑构造器。
那么为什么不只使用一个类呢?提出的替代方案:
class D(dict): # inheirits dict
   def __init__ (self,t,f,**attributes): # from is a keyword
       self['to'] = t
       self['from'] = f

       if(len(attributes) > 0):
           self.update(attributes)
       else:
           raise Exception("Require attribute")

d = D('jim','bob',item='book')
print d # {'to': 'jim', 'from': 'bob', 'item': 'book'}
print d['to'] # jim
print d['item'] # item
print d['from'] # bob

d = D('jim','bob') # throws error

显然,如果异步设置tofrom,这种方法会失效,但我认为基本思想仍然成立。创建一个类还可以使您更加详细地防止tofrom被覆盖/删除,并限制设置属性的最小/最大值。

嗯,一个有趣的解决方案,谢谢!不幸的是,看着我现在正在处理的代码,实现那个类将涉及大量的重构。但它似乎是一个合乎逻辑的解决方案。我将来会考虑实施它。再次感谢! - Vaibhav Aggarwal
1
由于它继承自字典,因此所有字典方法都得以保留,但我知道重构的痛苦。祝你好运。 - Dylan Madisetti

1
如果 d.keys() 的长度至少为3,并且它具有 from 和 to 属性,那么就满足条件。
我的 Python 知识不是很丰富,但我想代码应该是这样的:if len(d.keys) > 2 and d['from'] and d['to']

它是否可能有“from”、“item”和“weight”,而这些不是黄金的? - Dylan Madisetti
我的第二个约束需要一个“从”和一个“到”。 - David
1
如果属性不存在,d['from'] 将会抛出一个错误。 - Dylan Madisetti
1
如果它抛出一个错误,那么只需要检查另一种方式就可以了。逻辑是正确的。就像我说的,我不是Python专家,但这更多地涉及到逻辑而不是其他方面。 - David

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接