119

I have an uniform list of objects in python:

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

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

Now I want to extract a list with some attribute of that class (let's say attr), in order to pass it to some function (for plotting that data for example)

What is the pythonic way of doing the following:

attr = [o.attr for o in objs]

Maybe derive list and add a method to it, so I can use some idiom like objs.getattribute("attr")?

2

3 Answers 3

134

attrs = [o.attr for o in objs] was the right code for making a list like the one you describe. Don't try to subclass list for this. Is there something you did not like about that snippet?

2
  • I wonder what is "better" from both answers.With round brackets () or with square brackets []. ... The rest of the code is equal. Well, I understand that these are different ways of how it works internally. But as a Python newcomer I don't know if it doesn't matter, which way I should follow.
    – Beauty
    Commented Jan 27, 2021 at 9:25
  • @Beauty they do slightly different things, which might matter sometimes, for instance if you wanted to iterate over the result twice or reverse the result. Commented Jan 27, 2021 at 19:21
115

You can also write:

attr=(o.attr for o in objsm)

This way you get a generator that conserves memory. For more benefits look at Generator Expressions.

1
  • 1
    would accessing a specific entry result of a O(n) operation?. e.g would accessing index = 100 of attr[100] will result the generator to run 100 steps? Commented Jun 22, 2019 at 18:01
2

Another way could be to map getattr() on objs list.

# for a generator
from itertools import repeat
attrs = map(getattr, objs, repeat('attr'))
# or even without itertools
attrs = map(getattr, objs, ['attr']*len(objs))

# for a list
attrs = list(map(getattr, objs, repeat('attr')))

A nice thing about getattr is that a default value can be returned if no such attribute exist. For example, the below line returns 'NA' if attr is not defined in an object.

attrs = [getattr(o, 'attr', 'NA') for o in objs]

If multiple attributes need to be fetched, operator.attrgetter could be useful.

from operator import attrgetter
attrs = list(map(attrgetter('attr', 'other'), objs))

N.B. itertools and operator are in the standard library.

Not the answer you're looking for? Browse other questions tagged or ask your own question.