Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python - copy by reference

Is there any possibility to copy variable by reference no matter if its int or class instance?

My goal is to have two lists of the same objects and when one changes, change is visible in second.

In other words i need pointers:/


I simply want int, float and other standard types which are normally copied by value, force to copy by reference. This will make my code more consistent.

If there is no such possibility, class wrapper is the best solution.

like image 929
qba Avatar asked May 06 '10 18:05

qba


People also ask

Is Python copy by reference?

Python always uses pass-by-reference values. There isn't any exception. Any variable assignment means copying the reference value.

How do you pass a value by reference in Python?

Pass by reference means that you have to pass the function(reference) to a variable which refers that the variable already exists in memory. Here, the variable( the bucket) is passed into the function directly.

How do you copy instead of reference in Python?

To get a fully independent copy of an object you can use the copy. deepcopy() function.

Does Python copy by value?

Python passes arguments neither by reference nor by value, but by assignment.


2 Answers

Python always works by reference, unless you explicitly ask for a copy (a slice of a built-in list is deemed to "ask for a copy" -- but a slice of a numpy array also works by reference). However, exactly because of that, alist=anotherlist; alist.sort() means the single list objects (with two equivalent names alist and anotherlist) gets sorted -- you can't maintain two different orderings at the same time on the same list object.

So, in this case, you must explicitly ask for a copy (e.g. alist=list(anotherlist)) -- and once you've done that there is no more connection between the two distinct list objects. You can't have it both ways: either you work by reference (and have a single list object and thus a single ordering!), or you make a copy (in which case you end up with two separate list objects).

You could take advantage of the fact that the copies discussed so far are shallow -- the objects (items) that the two lists refer to are the same... until and unless you perform removals, additions, or reassignments of items on either list (mutation of mutable items on the other hand don't alter this connection: it's a completely separate and drastically different situation from any of the above, since removals, additions and reassignments are operation on the list, while calling a mutating method on an item is an operation on the item -- items are oblivious to any operation on one or more lists referring to them, lists are oblivious to any operation on one or more of the items they refer to).

There's not much you can do about removals and additions, except keeping two lists wrapped and synced up in a single object as suggested in other answers; but for reassignments of items, if that's all you require, you could turn those into mutation of items by adding one level of indirection -- instead of having a list directly referring to the items, have it refer e.g. to one-item sublists. For example:

>>> alist = list([x] for x in 'ciao')
>>> blist = list(alist)
>>> blist.sort()
>>> alist
[['c'], ['i'], ['a'], ['o']]
>>> blist
[['a'], ['c'], ['i'], ['o']]
>>> blist[-1][0] = 'z'
>>> blist
[['a'], ['c'], ['i'], ['z']]
>>> alist
[['c'], ['i'], ['a'], ['z']]

Whether this concept of an extra indirection level can help at all with what you're exactly trying to do, only you can tell, since we don't really know what it is that you are trying to do;-).

like image 112
Alex Martelli Avatar answered Sep 29 '22 08:09

Alex Martelli


You can wrap you immutable objects in a class:

class MutableWrapper(object):

    def __init__(self, value):
        self.value = value

a = MutableWrapper(10)
b = a
a.value = 20
assert b.value == 20
like image 40
Luper Rouch Avatar answered Sep 29 '22 08:09

Luper Rouch