1

Considering the following class :

class MyClass():
    def __init__(self,attr):
        self.attr=attr

and a list of MyClass objects :

myList=[MyClass(1),MyClass(2),MyClass(3)]

The attribute values are unique. To get the reference of the object with a specific value (for example : 2), I used

[i for i in myList if i.attr==2][0]

or

myList[[i.attr for i in myList].index(2)]

What is the best way to do that and is there a better solution ? (If I may, as I am a python beginner, answer with the pros and the cons of different solutions would be appreciated). (Rq : this example is very simple, list could be larger and objects more complex)

Thanks for answer.

Stef1611
  • 1,978
  • 2
  • 11
  • 30
  • 2
    You could put your objects in a dict with their attribute value as the key. – khelwood May 01 '21 at 18:12
  • 1
    Use a regular loop, dont use a list comprehension. Just `for x in my_list: if x.attr == 2: break` – juanpa.arrivillaga May 01 '21 at 18:17
  • 2
    If you're going to retrieve multiple elements from the list by attribute, organizing them into a dictionary as @khelwood suggested is what I'd recommend. Dictionaries allow fast retrieval by the target value after doing the initial work to construct one. If you're only going to retrieve a single element, take a look at the solutions here: https://stackoverflow.com/a/8534381/2337736 – Peter DeGlopper May 01 '21 at 18:17

1 Answers1

7

If you're sure the list contains an object with that attribute, you can use the following:

result = next(obj for obj in my_list if obj.attr == 2)

The above raises StopIteration if no such object is found, which may be undesirable especially if the code appears somewhere that a StopIteration would signal for some other loop to stop. To gracefully handle the case where an object is not found, you can provide a default value to be returned:

result = next((obj for obj in my_list if obj.attr == 5), None)

If this looks unwieldly, it's because lists aren't really meant to be used for this purpose. If you want to be able to easily (and efficiently) look up an object by one of its attributes, use a dictionary instead, and make that attribute the key.

my_dict = {obj.attr: obj for obj in my_list}

# raises KeyError if no such object exists
result = my_dict[2]

# returns None if no such object exists
result = my_dict.get(2)
kaya3
  • 47,440
  • 4
  • 68
  • 97