Reputation: 1411
Lets say I have a dictionary that specifies some properties for a package:
d = {'from': 'Bob', 'to': 'Joe', 'item': 'book', 'weight': '3.5lbs'}
To check the validity of a package dictionary, it needs to have a 'from'
and 'to'
key, and any number of properties, but there must be at least one property. So a dictionary can have either 'item'
or 'weight'
, both, but can't have neither. The property keys could be anything, not limited to 'item'
or 'weight'
.
How would I check dictionaries to make sure they're valid, as in having the 'to'
, 'from'
, and at least one other key?
The only method I can think of is by obtaining d.keys()
, removing the 'from'
and 'to'
keys, and checking if its empty.
Is there a better way to go about doing this?
Upvotes: 5
Views: 5129
Reputation: 775
This doesn't address the problem OP has, but provides what I think to be a better practice solution. I realize there's already been an answer but I just spent a few minutes reading on best practices and thought I would share
Problems with using a dictionary:
to
and from
are mandatory while item
and weight
are optionalSo why not just use a class? Proposed alternative:
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
Obviously this falls apart if to
and from
are set asynchronously but I think the base idea still holds. Creating a class also gives you the verbosity to prevent to
and from
from being overwritten/deleted as well as limiting the minimum/maximum of attributes set.
Upvotes: 1
Reputation: 239453
must = {"from", "to"}
print len(d) > len(must) and all(key in d for key in must)
# True
This solution makes sure that your dictionary has more elements than the elements in the must
set and also all the elements in must
will be there in the dictionary.
The advantage of this solution is that, it is easily extensible. If you want to make sure that one more parameter exists in the dictionary, just include that in the must
dictionary, it will work fine. You don't have to alter the logic.
Edit
Apart from that, if you are using Python 2.7, you can do this more succinctly like this
print d.viewkeys() > {"from", "to"}
If you are using Python 3.x, you can simply write that as
print(d.keys() > {"from", "to"})
This hack works because, d.viewkeys
and d.keys
return set-like objects. So, we can use set comparison operators. >
is used to check if the left hand side set is a strict superset of the right hand side set. So, in order to satisfy the condition, the left hand side set-like object should have both from
and to
, and some other object.
Quoting from the set.issuperset
docs,
set > other
Test whether the set is a proper superset of other, that is,
set >= other and set != other
.
Upvotes: 12
Reputation: 19264
Use the following code:
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()
Upvotes: 1
Reputation: 7456
if d.keys()
has a length of at least 3, and it has a from and to attribute, you're golden.
My knowledge of Python isn't the greatest but I imagine it goes something like if len(d.keys) > 2 and d['from'] and d['to']
Upvotes: 1