0

I wish to create a list that hold other value in a class and make sure that list is up to date without having to update it myself.

I have tried to write it this way:

class Test:
    def __init__(self, arg, arg2):
        self.arg = arg
        self.arg2= arg2
        self.list = [self.arg, self.arg2] #list I want up to date

    def update(self, arg, arg2):
        self.arg = arg
        self.arg2 = arg2
        #the simple answer is to add: self.list=[self.arg, self.arg2] or a function doing it. That is not what I am asking.

    def write_list(self):
        print(self.list)

tes = Test(1, 2)
tes.write_list()
tes.update(23,24)
tes.write_list()

I want the output to be:

[1,2]
[23,24]
  • 1
    for some types of data it always copy value - ie. for integes - for others it will use reference (pointer) and it will work as you expect - ie. for list or class. Some modules use classes to keep values like integer (`tkinter` has `IntVar`, `kivy` has `PropertyInteger`) and then list will keep references/pointers - but it may need class' method to set/get value - `val = IntVar.get()`, `IntVar.set(val)` – furas Aug 15 '19 at 02:36
  • It depends on the data types of `arg` and `arg2`. If they are immutable (such as `int`) you can't do that. If they are not, you can simply mutate them (such as `self.arg.update(arg)`) and that will also be reflected in the list. – Selcuk Aug 15 '19 at 02:36
  • Alright thank you for the answers! It's as I thought then, no way of doing that with minimal code. – Yordan Azzolin Aug 15 '19 at 02:42
  • @furas: Python does not copy integers. Variables holding integers really hold references to integers, just like with lists and any other Python data type. It's just that you can't do anything to mutate an int, while you can mutate a list. – user2357112 Aug 15 '19 at 02:43
  • 1
    Also see https://nedbatchelder.com/text/names.html – user2357112 Aug 15 '19 at 02:43
  • @furas not true, assignment **never copies** in python, regardless of the type. Immutable objects merely lack mutator methods. – juanpa.arrivillaga Aug 15 '19 at 03:00

2 Answers2

1

int is immutable. So when you do self.arg=arg in your update method, self.list will be still pointing to the old values.

What I recommend is to create a Pointer class to store your integers, with an update method to mutate the values:

class Test:
    def __init__(self, arg, arg2):
        self.arg = Pointer(arg)
        self.arg2= Pointer(arg2)
        self.list = [self.arg, self.arg2]

    def update(self, *args):
        for pointer, val in zip(self.list, args):
            pointer.update(val)

    def write_list(self):
        print (self.list)

class Pointer:
    def __init__(self, num):
        self.num = num

    def update(self, num):
        self.num = num

    def __repr__(self):
        return repr(self.num)

tes = Test(1, 2)
tes.write_list()
tes.update(23,24)
tes.write_list()

#[1, 2]
#[23, 24]
Henry Yik
  • 22,275
  • 4
  • 18
  • 40
  • 2
    Immutability is almost a red herring. Even if `self.arg` were referencing a mutable object, then `self.arg=arg ` wouldn't mutate anything. – juanpa.arrivillaga Aug 15 '19 at 03:03
  • Yes, but I think in OP's concept he was expecting `self.list`, a list that stores `self.arg` and `self.arg2`, will be mutated when a new value of `self.arg` is defined. – Henry Yik Aug 15 '19 at 03:07
0

One alternative is to use a property, where lst mimicks a traditional attribute but actually is re-created at runtime. There's some inefficiencies in this, however, since the list is being re-created each time you access test_instance.lst.

class Test:
    def __init__(self, arg1, arg2):
        self.arg1 = arg1
        self.arg2 = arg2

    @property
    def lst(self):
        return [self.arg1, self.arg2]

    def update(self, arg1, arg2):
        self.arg1 = arg1
        self.arg2 = arg2

    def write_list(self):
        print(self.lst)

tes = Test(1, 2)
tes.write_list()
tes.update(23,24)
tes.write_list()

# Output:
#   [1, 2]
#   [23, 24]

Another option, at least with the example code, would just be to update the .lst attribute from within .update():

class Test:
    def __init__(self, arg1, arg2):
        self.arg1 = arg1
        self.arg2 = arg2
        self.lst = [arg1, arg2]

    def update(self, arg1, arg2):
        self.arg1 = arg1
        self.arg2 = arg2
        self.lst = [arg1, arg2]

    def write_list(self):
        print(self.lst)

tes = Test(1, 2)
tes.write_list()
tes.update(23,24)
tes.write_list()
jedwards
  • 29,432
  • 3
  • 65
  • 92
  • That is very interesting, can you quickly tell me how @property works? – Yordan Azzolin Aug 15 '19 at 04:45
  • [`@property`](https://docs.python.org/3/library/functions.html#property) is a method decorator that allows you to "emulate" an attribute (e.g. `test.lst`) with the return value of a method call. The docs (linked), as well as [this question/answers](https://stackoverflow.com/questions/17330160/how-does-the-property-decorator-work) may be helpful – jedwards Aug 15 '19 at 20:59