66

In the code:

y = 7
x = y
x = 8

Now, y will be 7 and x will be 8. But actually I wan to change y. Can I assign the reference of y and do that?

For example, in C++ the same thing can be achieved as:

int y = 8;
int &x = y;
x = 9;

Now both y & x will be 9

viji
  • 2,706
  • 5
  • 28
  • 34

4 Answers4

78

No, you cannot. As other answer point out, you can (ab?)use aliasing of mutable objects to achieve a similar effect. However, that's not the same thing as C++ references, and I want to explain what actually happens to avoid any misconceptions.

You see, in C++ (and other languages), a variable (and object fields, and entries in collections, etc.) is a storage location and you write a value (for instance, an integer, an object, or a pointer) to that location. In this model, references are an alias for a storage location (of any kind) - when you assign to a non-reference variable, you copy a value (even if it's just a pointer, it's still a value) to the storage location; when you assign to a reference, you copy to a storage location somewhere else. Note that you cannot change a reference itself - once it is bound (and it has to as soon as you create one) all assignments to it alter not the reference but whatever is referred to.

In Python (and other languages), a variable (and object fields, and entries in collections, etc.) is a just a name. Values are somewhere else (e.g. sprinkled all over the heap), and a variable refers (not in the sense of C++ references, more like a pointer minus the pointer arithmetic) to a value. Multiple names can refer to the same value (which is generally a good thing). Python (and other languages) calls whatever is needed to refer to a value a reference, despite being pretty unrelated to things like C++ references and pass-by-reference. Assigning to a variable (or object field, or ...) simply makes it refer to another value. The whole model of storage locations does not apply to Python, the programmer never handles storage locations for values. All he stores and shuffles around are Python references, and those are not values in Python, so they cannot be target of other Python references.

All of this is independent of mutability of the value - it's the same for ints and lists, for instance. You cannot take a variable that refers to either, and overwrite the object it points to. You can only tell the object to modify parts of itself - say, change some reference it contains.

Is this a more restrictive model? Perhaps, but it's powerful enough most of the time. And when it isn't you can work around it, either with a custom class like the one given below, or (equivalent, but less obvious) a single-element collection.

class Reference:
    def __init__(self, val):
        self._value = val # just refers to val, no copy

    def get(self):
        return self._value

    def set(self, val):
        self._value = val

That still won't allow you to alias a "regular" variable or object field, but you can have multiple variables referring to the same Reference object (ditto for the mutable-singleton-collection alternative). You just have to be careful to always use .get()/.set() (or [0]).

  • 6
    Good explanation, +1 for clarifying that it has nothing to do with mutability. – Daniel Roseman Jun 27 '12 at 09:20
  • Can anyone explain the meaning of (ab?) in this answer? – Fady Hany Sep 24 '21 at 03:56
  • @Daniel Roseman Can you explain the meaning of (ab?) in this answer? – Fady Hany Sep 24 '21 at 09:38
  • This is a great answer and I think it's a good candidate to become a community answer. Adding example of languages for each paradigm could be very useful as well. – marco romelli Dec 03 '21 at 13:09
  • 3
    @FadyHany I think that you can read the part "you can (ab?)use aliasing" either as "you can use aliasing" or as "you can abuse aliasing", indicating that this workaround may be considered to be hacky by some developers. – Nos Dec 09 '21 at 22:04
21

No, Python doesn't have this feature.

If you had a list (or any other mutable object) you could do what you want by mutating the object that both x and y are bound to:

>>> x = [7]
>>> y = x
>>> y[0] = 8
>>> print x
[8]

See it working online: ideone

Mark Byers
  • 811,555
  • 193
  • 1,581
  • 1,452
  • 1
    Although this is really helpful there is more or less big downside in this "mutation" of a single simple numerical value. Turning the integer in a list with a single element requires little more than 3 times the memory space you'll normally need. Example (I'll use sys.getsizeof(...) to illustrate the size-difference): x = 1 -> sys.getsizeof(x) -> give us 14 -> x = [1] -> sys.getsizeof(x) -> gives us 36 – rbaleksandar Sep 24 '13 at 19:34
8

Alternatively, you could use a self crafted container.

class Value(object):
    def __init__(self, value): self.value = value

y = Value(7)
x = y
x.value = 8
print y.value

ideone

glglgl
  • 89,107
  • 13
  • 149
  • 217
7

You should use a mutable object for this.

In python x & y are just references to objects so y = 7 means y points to the object 7. x=y means x too points to 7, but as 7 is immutable so changing the value of x simply changes the object 7 and y still remains pointing to 7.

>>> y = [7]
>>> x = y
>>> x[0] = 8 # here you're changing [7] not x or y, x & y are just references to [7]
>>> y
[8]
Ashwini Chaudhary
  • 244,495
  • 58
  • 464
  • 504