ids = []
for object in objects:
ids += [object.id]
-
Note that `ids += [object.id]` is usually written simply as `ids.append(object.id)`. – Eric O. Lebigot Oct 15 '10 at 09:12
-
@Tumbleweed: `object` is not a keyword, it's a built-in function. had it been a keyword this code would raise a `SyntaxError`. – SilentGhost Oct 15 '10 at 15:11
-
ye right its builtin type - but I would suggest not to replace it !! – shahjapan Oct 16 '10 at 02:24
-
Possible duplicate of [How to extract from a list of objects a list of specific attribute?](https://stackoverflow.com/questions/677656/how-to-extract-from-a-list-of-objects-a-list-of-specific-attribute) – Georgy Oct 26 '18 at 09:00
4 Answers
You can use a list comprehension:
ids = [object.id for object in objects]
For your reference:
Both produce the same result. In many cases, a list comprehension is an elegant and pythonic way to do the same as what you mentioned.
-
Gives also minimal scope for the hiding of object function. Somehow does not look so bad as original in this point also. – Tony Veijalainen Oct 15 '10 at 18:45
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.

- 92,761
- 29
- 141
- 204
-
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 Oct 15 '10 at 13:15
-
@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`. – tzot Oct 15 '10 at 13:33
-
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 Oct 15 '10 at 13:51
-
@aaron: yep, same results here. The age-old suggestion to “never guess, always time” applies :) – tzot Oct 15 '10 at 14:02
-
1@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). – tzot Oct 21 '10 at 07:07
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]

- 8,814
- 9
- 58
- 88
-
1I'm curious, too, rubik. Maybe someone has puritanical beliefs about the '_' name. In any case, I've brought you back to zero. – Cameron Laird Oct 21 '10 at 16:10
-
Thank you. But I usually use the '_' in for loops where I don't need the counter... – rubik Oct 21 '10 at 18:25
-
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 Oct 22 '10 at 17:29