Joren
Joren

Reputation: 3315

Elegant pythonic solution for a simple loop

The function bars takes a list of Foo objects and returns a list of the bar attributes of those:

 def bars(foos):
      bars = []
      for foo in foos:
          bars.append(foo.bar)
      return bars

Coming from a Java background, this is the way I would have solved this in the past. But I feel that there is a more elegant pythonic way to solve this. How would I do that?

Upvotes: 0

Views: 1129

Answers (2)

Lukas Graf
Lukas Graf

Reputation: 32650

For your example, @Korem's suggestion of a list comprehension is the ideal solution.

But here's an alternative for when you encounter that pattern where you

  • initialize an empty sequence
  • append to it in a loop
  • return the sequence

but maybe need to do some more heavy lifting that you can't simply express in an expression (list comprehensions don't allow statements, only epxressions) - create a generator function:

def bars(foos):
    for foo in foos:
        yield foo.bar

There's just two things to note:

  • Generator functions don't return a sequence, they return a generator. That generator needs to be consumed by iterating over it. If you would use it like a sequence (indexing its elements for example), you'd need to turn it into a sequence e.g. by doing list(bars(f)):
>>> gen = bars(f)
>>> gen[0]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'generator' object has no attribute '__getitem__'
>>>
>>> list(gen)[0]
42
  • Once you iterate over it the generator will be exhausted:
>>> gen = bars(f)
>>> list(gen)
[42, 42, 42]
>>> list(gen)
[]

Upvotes: 1

tktk
tktk

Reputation: 11754

Use list-comprehensions:

[foo.bar for foo in foos]

(You can wrap it with def bars(foos):, but I think it's more readable without it)

Upvotes: 6

Related Questions