1

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.

ITA
  • 3,200
  • 3
  • 18
  • 32

1 Answers1

6

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)
Bharel
  • 23,672
  • 5
  • 40
  • 80
  • 2
    I didn't know about `operator.attrgetter`. That seems to be a handy module. I should have understood what I was trying to do is exactly [this](https://stackoverflow.com/questions/11173660/can-one-partially-apply-the-second-argument-of-a-function-that-takes-no-keyword). – ITA Sep 09 '20 at 23:46