Python get instance from list based on instance variable
Given a list of instances, say clients
I'm trying to pluck an item from the list based on the value of a single instance variable screenName
. I know I can do this:
for client in clients:
if client.screenName = search:
return client
开发者_开发技巧But is there a nicer way of doing this without the loop?
Thanks for your help :)
You can use filter
try:
filter(lambda client: client.screenName == search, clients)[0]
except IndexError:
# handle error. May be use a default value
I would use list comprehensions. Suppose this is your Client
class:
>>> class Client:
... def __init__(self, screenName):
... self.screenName = screenName
If I got this list of clients:
>>> l = [Client('a'), Client('b'), Client('c')]
...I can get a list containing only the clients with a given name:
>>> [e for e in l if e.screenName == 'b']
[<__main__.Client instance at 0x2e52b0>]
Now, just get the first - and assumedly only - element:
>>> [e for e in l if e.screenName == 'b'][0]
<__main__.Client instance at 0x2e52b0>
>>> c = [e for e in l if e.screenName == 'b'][0]
>>> c.screenName
'b'
This is pretty short and IMHO elegant but can be less efficient because the list comprehension will iterate over all the list. If you do want to avoid this overhead, you can get an generator instead of a new list using parenthesis instead of square brackets:
>>> g = (e for e in l if e.screenName == 'b')
>>> g
<generator object <genexpr> at 0x2e5440>
>>> g.next()
<__main__.Client instance at 0x2e52b0>
However, note that the next()
method can be called just once.
HTH!
You could use a generator expression,
client=next(client for client in clients if client.screenName == search)
but not that you still looping, just in a different way.
Note: If no client satisfies the condition client.screenName == search
then the above will raise a StopIteration
exception. This is different than your for-loop
, which falls out of the loop without returning anything.
Depending on your situation, raising an exception might be better than failing silently.
If you do not want a default value instead of a StopIteration
exception, then you could use the 2-parameter version of next
:
client=next(client for client in clients if client.screenName == search,
default_value)
using a dictionary for this:
assuming this :
d[screeName] = client
you can just do this:
return d[search]
If clients
is a dict
then you can just use clients[search]
. If the order of elements in your list is important, then you can use an OrderedDict
from collections
.
Best discussion of this topic is on this link
return find(lambda client: client.screenName == search, clients)
This requires you define a generic find function which would work for all types of lists like thus:
def find(f, seq):
"""Return first item in sequence where f(item) == True."""
for item in seq:
if f(item):
return item
精彩评论