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 :)