1

I have an object with an attribute that is a list. For example:

obj.a = [3, 4, 5]

I would like to get the following behavior (but I can't manage to find a solution using magics/etc.) :

l = obj.a
obj.a[0] = 2

print(l) --> [3, 4, 5]
print(obj.a) ---> [2, 4, 5]

Of course I could simply use copy.deepcopy :

l = copy.deepcopy(obj.a) 

but for several reasons I would like, somehow, to make this step automatic/hide it for my users.

[EDIT] Using getattribute and returning a copy won't work of course:

import copy
class Test:
    def __init__(self):
         self.a = []

    def __getattribute__(self, attr):
        if attr == 'a':
            return copy.deepcopy(super(Test, self).__getattribute__(attr))

Any help appreciated !

Thnak you, Thomas

Thomas C.
  • 85
  • 1
  • 4
  • 3
    This isn't possible without explicitly copying the list during the operations when you want to be working with a copy and leaving it during operations when you don't. In other words, from python's perspective, there is nothing different about the `obj.a` access from the first line to the second line so there is no magic signal which would allow you to hide a copy operation for some cases and not others. – mgilson Sep 02 '16 at 06:55
  • Possible duplicate of [How to clone or copy a list in Python?](http://stackoverflow.com/questions/2612802/how-to-clone-or-copy-a-list-in-python) – deceze Sep 02 '16 at 06:57
  • 1
    You could override the `obj.a` property to always return a copy of the list… however, that would be rather expensive and break a lot of assumptions where you *do* expect the normal behaviour of *not* copying. Make it explicit when you need a copy, period. – deceze Sep 02 '16 at 06:59
  • Ok, thank you, this is the answer I was expecting. No magic signal then ! – Thomas C. Sep 02 '16 at 07:03
  • 1
    You may find this article helpful: [Facts and myths about Python names and values](http://nedbatchelder.com/text/names.html), which was written by SO veteran Ned Batchelder. – PM 2Ring Sep 02 '16 at 08:06

3 Answers3

1

It's not possible to make the assignment l = obj.a make a copy of obj.a. As deceze said in a comment, you could make a a property that returns a copy of the value every time you access it, but that would, well, make a copy every time you access it, not just when you assign it to l. That's going to be inefficient, and probably not the behavior you want anyway

There's no way for obj or obj.a to tell the difference between something like this:

x = obj.a

and this:

obj.a[:2]

Whatever happens when you access obj.a, it's going to happen in both cases. You can't "look ahead" to see whether it's going to be assigned to a variable, just to copy it in that particular case.

BrenBarn
  • 242,874
  • 37
  • 412
  • 384
  • Thank you for your answer. I guess the behavior I wanted is close to what is called Value Class in some languages! – Thomas C. Sep 15 '16 at 15:26
0

Simply use the following code...

l = list(obj.a)

this will allow you to copy a list to a new list

Gautam Krishna R
  • 2,388
  • 19
  • 26
0

This is not possible without actually cloning the list to another list, you have to use copy() or deepcopy() depending on your requirement.

Sunil Lulla
  • 797
  • 10
  • 18