开发者

**kwargs search mechanism in an object (python)

开发者 https://www.devze.com 2022-12-10 10:53 出处:网络
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:

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)
0

精彩评论

暂无评论...
验证码 换一张
取 消