0

How to access attributes of classes in list without a for loop? I've been creating lists and looping through them is inefficient so am trying to avoid if so for clean code.

kill_the_loop.py

# Define our arbitrary class
class IntRelationships(object):
    def __init__(self, a, b):
        self.a = a
        self.b = b
        self.diff = abs(b-a)
    def add(self):
        return self.a + self.b

# create a class list
relationship_list = [ IntRelationships(1,2), IntRelationships(2,4), IntRelationships(4, 8)]

# How I currently access attributes in list
large_diff_list = []
for relationship in relationship_list:
    if relationship.diff > 1:
        large_diff_list.append(relationship)

# How imagine one could do it without a loop and array initialisation
large_diff_list2 = relationship_list[ relationship_list[:].diff > 1 ]
1
  • 1
    That code is clean, idiomatic, and pythonic. It is not inefficient. You could convert this into a list-comprehension, but it's fine as is. Commented Mar 13, 2019 at 3:07

2 Answers 2

2

You can use a list comprehension:

large_diff_list = [r for r in relationship_list if r.diff > 1]
Sign up to request clarification or add additional context in comments.

Comments

1

There isn't really any getting around how much computation is required to access an attribute on n items - you'll need to loop over all n of them somehow. But if you're worried about being efficient with memory usage, you might be able to use a generator instead of making a list. A generator only creates the next element when it's needed, so you don't have to store everything in memory at once. The downside is, you no longer have random access to the items. So, this makes sense if you just want to do a for loop over the generator, but not if you want to access items repeatedly / at specific positions. Of course, you can always convert a generator to a list by calling list(my_generator).

large_diff_generator = filter(lambda relationship: relationship.diff > 1, relationship_list)

EDIT: I was wrong about the value returned from filter being a generator. It is an iterable, and like a generator, it does not pre-compute each value but instead computes them one at a time as needed. You can verify this as follows:

from typing import Generator, Iterable
evens = filter(lambda x: x % 2 == 0, range(100000000000000000000000000000))
isinstance(evens, Generator)  # False
isinstance(evens, Iterable)  # True

1 Comment

Note: filter does not create a generator.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.