tags:

views:

262

answers:

4
ids = []

for object in objects:
  ids += [object.id]
+23  A: 

You can use list comprehension

ids = [object.id for object in objects]

For you reference:

Both produce the same result. In many cases, List comprehension is a elegant and pythonic way to do the same thing, you have mentioned.

pyfunc
Exactly what I was looking for. Thanks!
cyberguijarro
@cyberguijarro: Do not forget to accept the answer if that was what you were looking for. (Click the tick under the votes count)
jhominal
Gives also minimal scope for the hiding of object function. Somehow does not look so bad as original in this point also.
Tony Veijalainen
+3  A: 

Another way:

ids = map(lambda x: x.id, objects)
anti_social
it's not equivalent to OP's code in py3k
SilentGhost
+2  A: 

The standard (i.e “pythonic” a.k.a cleanest :) way is to use a list comprehension:

ids= [obj.id for obj in objects]

The above works for all Python versions ≥ 2.0.

Other ways (just FYI)

In Python 2, you can also do:

ids= map(lambda x: x.id, objects)

which should be the slowest method, or

# note: Python ≥ 2.4
import operator
ids= map(operator.attrgetter('id'), objects)

which might be the fastest method, although I assume the difference won't be that much; either way, the clarity of the list comprehension outweighs speed gains.

Should you want to use an alternative way in Python 3, you should enclose the map call in a list call:

ids= list(map(operator.attrgetter('id'), objects))

because the map builtin returns a generator instead of a list in Python 3.

ΤΖΩΤΖΙΟΥ
in this case the list comprehension is twice as fast as mapping `lambda` which is itself around ten percent faster than mapping `attrgetter('id')` (surprised me too)
aaronasterling
@aaron: I'm also surprised; please provide some sample `objects` where `lambda` is *faster* than mapping `attrgetter`; if `id` is a simple attribute (i.e not a property), `attrgetter` should be faster than `lambda`.
ΤΖΩΤΖΙΟΥ
the test I used was `class Foo(object): def __init__(self, id_): self.id = id_`. The time was linear so it didn't make a difference if the list had one element or 10000.
aaronasterling
@aaron: yep, same results here. The age-old suggestion to “never guess, always time” applies :)
ΤΖΩΤΖΙΟΥ
@aaron: there was an issue in the operator.c code after the ability to process dotted names, and attrgetter was slowed down; I've submitted a [patch](http://bugs.python.org/issue10160) that once again makes `attrgetter` run almost twice as fast as the `lambda`. Hopefully the issue will be resolved. (And, wow: my usage of English is deteriorating very fast since last midnight; I need some sleep).
ΤΖΩΤΖΙΟΥ
+1 Nice work. Let's hope rhett lets it go through.
aaronasterling
+1  A: 

You don't need the operator module:

In [12]: class Bar(object):
             def __init__(self, id_):
                 self.id = id_         

In [15]: foo = [Bar(1) for _ in xrange(10000)]

In [16]: foobar = map(lambda bar: getattr(bar, 'id'), foo)

In [17]: len(foobar)
Out[17]: 10000

In [18]: foobar[:10]
Out[18]: [1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
rubik
Why someone voted me down?
rubik
I'm curious, too, rubik. Maybe someone has puritanical beliefs about the '_' name. In any case, I've brought you back to zero.
Cameron Laird
Thank you. But I usually use the '_' in for loops where I don't need the counter...
rubik
I didn't vote you down, but there are actually good reasons not to use `_` as temporary variable. As the variable remains in the current scope, you cannot use gettext's `_` anymore in the same function (if you imported `gettext.gettext` as `_` for translation). I usually call such variables "unused" or "unused_xyz" because then PyDev doesn't show a warning about it being actually unused.
AndiDog
Ah ok! I understood.
rubik