What is the 'correct' way to alter one element from a list attribute?

53 Views Asked by At

Consider the following piece of code

class Point:
    def __init__(self, x, y):
        self.x = x
        self.y = y

class Widget:
    def __init__(self, low=None, mid=None, high=None):
        self.low = low
        self.mid = mid
        self.high = high

widget = Widget(low=[Point(0, 1), Point(1, 2), Point(2, 3)],
                mid=[Point(3, 4), Point(4, 5), Point(5, 6)],
                high=[Point(6, 7), Point(7, 8), Point(8, 9)])

a, b, c = Point(11, 11), Point(12, 12), Point(13, 13)

Now I would like to alter the attributes of the widget instance. Each attribute has to be altered in a certain way. Specifically, let us consider the (simplified) example where the first element of widget.low needs to be set to a, the second element of widget.mid to b and the last element of widget.high to c. Since these operations are very similar I am tempted to write it in a nested fashion like so,

for attr, ix, value in (('low', 0, a), ('mid', 1, b), ('high', 2, c):
    getattr(widget, attr)[ix] = value

Now, this feels very naughty. Because, I am using getattr to set (part of) an attribute. In this the first answer states that setting attributes should be done by setattr. The above construction would then become something like,

for attr, ix, value in (('low', 0, a), ('mid', 1, b), ('high', 2, c):
    setattr(widget, attr, getattr(widget, attr)[:ix] + [value] + getattr(widget, attr)[ix+1:])

Wow! That is really ugly. I believe the result of these two loops is the same, for instance, as expected self.mid = [Point(3,4), Point(12, 12), Point(5,6)] . I am interested in the 'correct' (most pythonic) way to do this? I know 'flat is better than nested' and for this task I could write out three lines. But I am considering a situation where nesting can save a significant amount of duplication. Thanks in advance :)

0

There are 0 best solutions below