I apologize if am completely missing something obvious or if I have not dug into the documentation hard enough, but after 30 mins or so I found a work around (without having understood the error I was getting) and ... hence the question here. Suppose I have a class:
class RGB(object):
def __init__(self, r, g, b):
super(RGB, self).__init__()
self.red = r
self.blue = b
self.green = g
and I define a list of RGB
instances as follows:
from random import random
rr, gg, bb = [[random() for _ in range(20)] for _ in range(3)]
list_of_rgbs = [RGB(*item) for item in zip(rr, gg, bb)]
why can't I extract a list of red
values by doing:
from functools import partial
*reds, = map(partial(getattr, name="red"), list_of_rgbs)
or
*reds, = map(partial(getattr, "red"), list_of_rgbs)
I know I can make it do what I want by saying reds = [x.red for x in list_of_rbgs]
but that would be difficult if the list of attributes to extract comes from elsewhere like: attribs_to_get = ['red', 'blue']
. In this particular case I can still do what I want by:
reds, blues = [[getattr(x, attrib) for x in list_of_rgbs] for attrib in attribs_to_get]
but my question is about what causes the error. Can someone explain why, or how to make it work using partial
and map
? I have a hunch it has something to do with this behavior (and so maybe the partial function needs a reference to self
?) but I can't quite tease it out.
For reference I was on Python 3.7.
Partial can only set positional arguments starting at the first argument. You can't set the second argument as positional, but only as a keyword argument. As the first one for getattr
is the object, it won't work well together with map
and partial
.
What you can use however is operator.attrgetter()
:
from operator import attrgetter
*reds, _ = map(attrgetter("red"), list_of_rgbs)