**kwargs search mechanism in an object (python)
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 doe开发者_如何学Pythonsn'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!
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.
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)
精彩评论