-1

I am trying to subclass list in order to create an in-place method that updates self with the item-wise sum of itself and a new list. Example:

This is how I tried to do it:

class RecordBook(list):
    def accumulate(self, new_values):
        self = RecordBook([x+y for x, y in zip(self, new_values)])

With the though being that rebinding back to self will modify it in-place. It does not work however.

>> d = RecordBook([1, 2, 3, 4, 5, 6])
>> d
[1, 2, 3, 4, 5, 6]
>> d.accumulate([1]*6)
>> d
[1, 2, 3, 4, 5, 6]  # should have been [2, 3, 4, 5, 6, 7]

Why is that failing the task and how would one go about this?

Reblochon Masque
  • 35,405
  • 10
  • 55
  • 80
Ma0
  • 15,057
  • 4
  • 35
  • 65
  • 4
    You're not *modifying* the instance, you're trying to *replace* the instance with a completely new instance. Don't do that. You want something like `self[:] = [...]` to modify an existing list. – deceze Oct 13 '20 at 06:58
  • @deceze You are totally right but I still don't get why it did not work – Ma0 Oct 13 '20 at 07:00
  • You probably want to subclass [`collections.UserList`](https://docs.python.org/3/library/collections.html#collections.UserList) i/o `list` – Reblochon Masque Oct 13 '20 at 07:01
  • Because `self` is just a local variable, and assigning something else to it doesn't replace the existing object. `a = 'foo'; b = a; b = 42` — Did that replace or modify `a`? Nope. – deceze Oct 13 '20 at 07:03
  • "but I still don't get why it did not work" Because nothing in Python ever works that way. If you do `a = []` and `b = a` and then `b = 3`, `a` does not become `3`. – Karl Knechtel Oct 13 '20 at 07:16
  • @KarlKnechtel If these two examples are equivalent, my understanding of `self` was flawed. Thanks! – Ma0 Oct 13 '20 at 07:49
  • `self` is just another parameter. The magic is done [elsewhere](https://docs.python.org/3/howto/descriptor.html). – Karl Knechtel Oct 13 '20 at 10:50

1 Answers1

1

Here is one approach subclassing collections.UserList, and modifying the underlying self.data of the subclass.

As explained by @Deceze in the comments:

self is just a local variable, and assigning something else to it doesn't replace the existing object

UserList exposes the self.data attribute that can be modified "in-place"

from collections import UserList


class Accumulator(UserList):
    def accumulate(self, seq):
        for idx, elt in enumerate(seq):
            self.data[idx] += elt


if __name__ == '__main__':
    d = Accumulator([1, 2, 3, 4, 5, 6])
    d.accumulate([1]*6)
    print(d)

output:

[2, 3, 4, 5, 6, 7]
Reblochon Masque
  • 35,405
  • 10
  • 55
  • 80