1

How do I insert a list (or numpy array) containing attribute values into a list of objects (as shown below)?

class myClass(object):
    def __init__(self, attr):
        self.attr = attr
        self.other = None

objs = []
for i in range(10):
        objs.append(myClass(i))

attrs = [o.attr for o in objs]
print attrs
#[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

[o.attr for o in objs] = range(10)
#SyntaxError: can't assign to list comprehension

This is the inverse problem to Extract list of attributes from list of objects in python.

Community
  • 1
  • 1
akk
  • 259
  • 2
  • 8

2 Answers2

3

I'd do something like this:

for i, o in enumerate(objs):
    o.attr = i

enumerate(objs) is sort of like zip(range(len(objs)), objs), so in case you actually want to take values from another sequence, you can:

for i, o in zip(sequence, objs):
    o.attr = i

For efficiency you might use itertools.izip there too.

John Zwinck
  • 239,568
  • 38
  • 324
  • 436
  • +1, I was just about to suggest you might want to give a more general solution, but then it appeared. As a tiny note on style, personally, I'd make `sequence` and `obj` appear the other way around in the call to `zip()` (and naturally swapping `i, o` to `o, i` to keep the functionality the same) as it would then mirror the order the objects are used in the code. Not important or changing any functionality, but I'd argue it's a little more readable. – Gareth Latty Jul 04 '13 at 10:45
  • @Lattyware: I'd swap the order in the zip too in practice, but here I kept it the same to avoid distracting from the point that the zip with range is equivalent to enumerate. – John Zwinck Jul 04 '13 at 10:48
1

You can also use obj.__setattr__() within a list comprehension:

[o.__setattr__('attr',v) for o,v in zip(objs,range(10)[::-1])]
print [o.attr for o in objs]
#[9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
ali_m
  • 71,714
  • 23
  • 223
  • 298
  • -1 - this is reimplementing the wheel (`setattr()` exists), and it's using list comprehensions for side effects, which is a terrible idea. – Gareth Latty Jul 04 '13 at 11:54
  • Quite right, that was very sloppy of me. Here's a slightly less moronic answer that uses the built in `__setattr__` method, although if it was me I'd still use John Zwinck's approach. – ali_m Jul 04 '13 at 12:16
  • Why access the magic method directly? And this still uses a list comprehension for side effects. – Gareth Latty Jul 04 '13 at 12:29
  • I know it's ugly, just pointing out that it can actually be done in a list comprehension if you don't mind courting the hatred of other Python programmers :) – ali_m Jul 04 '13 at 13:20
  • @Lattyware interesting to see the pythonic aversion towards 'comp lists for side effects', coming from Matlab I would have assumed that if a single code line is used to get the data, a single code line can be used to set the data... I guess this explains it http://stackoverflow.com/questions/5753597/is-it-pythonic-to-use-list-comprehensions-for-just-side-effects – akk Jul 05 '13 at 11:23
  • @akk Python is designed around the idea code is read more than it is written. One liners may be fun/fast to write, but they often suck to read. If you don't need to build a list, don't use a list comp, it's wasteful and just makes coder harder to read. – Gareth Latty Jul 06 '13 at 17:10