Reputation: 10969
Want to be able to provide a search interface for a collection of objects to be used by passing a list of keyword arguments like so:
playerID = players.search(nameFirst='ichiro', nameLast='suzuki')
Where players.search is defined like so:
def search(self, **args):
ret = []
for playerID, player in self.iteritems():
for key, value in args.iteritems():
if getattr(player, key) == value:
ret.append(player.playerID)
return ret
Obviously the above code doesn't work. I want to, to borrow some SQL idioms, to work like where player.key == value and player.keyN = valueN, and so on for N number of kwargs passed.
Any ideas? Thanks!
Upvotes: 0
Views: 184
Reputation: 882421
I want to, to borrow some SQL idioms, to work like where player.key == value and player.keyN = valueN, and so on for N number of kwargs passed.
So you're currently implementing an OR and want to implement an AND instead -- is that it?
If so, then the all
suggested in @Mark's answer would work -- or alternatively, and equivalently albeit at a lower level of abstraction:
def search(self, **args):
ret = []
for playerID, player in self.iteritems():
for key, value in args.iteritems():
if getattr(player, key) != value: break
else:
ret.append(player.playerID)
return ret
I'm not quite sure why you're looping on iteritems
and then ignoring the key you're getting (appending player.playerID
rather than the playerID
key directly).
Anyway, another high-abstraction approach, assuming you don't need the keys...:
def search(self, **args):
def vals(p):
return dict((k, getattr(p, k, None)) for k in args)
return [p.playerID for p in self.itervalues() if vals(p) == args]
This one doesn't "short-circuit" but is otherwise equivalent to Mark's. Fully equivalent, but quite concise:
def search(self, **args):
return [p.playerID for p in self.itervalues()
if all(getattr(p, k, None)==args[k] for k in args)]
If these code snippets don't meet your needs, and you can clarify why exactly they don't (ideally with an example or three!-), I'm sure they can be tweaked to satisfy said needs.
Upvotes: 1
Reputation: 258388
You should be able to change it to a list comprehension with the all
builtin, which returns True iff all the elements in its argument are true (or if the iterable is empty). Something like this should do the trick:
for playerID, player in self.iteritems():
if all(getattr(player, key) == value for key, value in args.iteritems()):
ret.append(player.playerID)
Upvotes: 1