1

I am looking for the proper term to describe this well-known property of collection objects, and more importantly, the way the stack diagram changes when variables are used to reference their elements:

>>> x = 5
>>> l = [x]
>>> x += 1
>>> l
[5]
>>> x
6

What is the name of what the list is doing to the variable x to prevent it from being bound to any changes to the original value of x? Shielding? Shared structure? List binding? Nothing is coming back from a Google search using those terms.

Here's an example with more detail (but doesn't have a definition, unfortunately).

an example of list structure sharing

Credit to ocw.mit.edu

Stanislav Kralin
  • 11,070
  • 4
  • 35
  • 58
yurisich
  • 6,991
  • 7
  • 42
  • 63
  • name binding? reference? – hochl Mar 20 '12 at 15:04
  • List scoping? List protection? – yurisich Mar 20 '12 at 15:14
  • 2
    The textbook example you provide is describing an unrelated phenomenon. In that example, the point is that `a` and `b` point at the same object, while `c` points at a copy. So altering the object pointed at by `a` and `b` doesn't alter the object pointed at by `c`. – senderle Mar 20 '12 at 15:51
  • 1
    Also, this is not only a property of lists, but a property of Python itself. – senderle Mar 20 '12 at 15:55

5 Answers5

5

What is the name of what the list is doing to the variable x to prevent it from being bound to any changes to the original value of x? Shielding? Shared structure? List binding? Nothing is coming back from a Google search using those terms.

Because the list isn't doing anything, and it isn't a property of collections.

In Python, variables are names.

>>> x = 5

This means: x shall be a name for the value 5.

>>> l = [x]

This means: l shall be a name for the value that results from taking the value that x names (5), and making a one-element list with that value ([5]).

>>> x += 1

x += 1 gets rewritten into x = x + 1 here, because integers are immutable. You cannot cause the value 5 to increase by 1, because then it would be 5 any more.

Thus, this means: x shall stop being a name for what it currently names, and start being a name for the value that results from the mathematical expression x + 1. I.e., 6.

That's how it happens with reference semantics. There is no reason to expect the contents of the list to change.


Now, let's look at what happens with value semantics, in a hypothetical language that looks just like Python but treats variables the same way they are treated in C.

>>> x = 5

This now means: x is a label for a chunk of memory that holds a representation of the number 5.

>>> l = [x]

This now means: l is a label for a chunk of memory that holds some list structure (possibly including some pointers and such), which will be initialized in some way so that it represents a list with 1 element, that has the value 5 (copied from the x variable). It cannot be made to contain x logically, since that is a separate variable and we have value semantics; so we store a copy.

>>> x += 1

This now means: increment the number in the x variable; now it is 6. The list is, again, unaffected.

Regardless of your semantics, you cannot affect the list contents this way. Expecting the list contents to change means being inconsistent in your interpretations. (This becomes more obvious if you rewrite the code to l = [5]; x = l[0]; x += 1.)

Karl Knechtel
  • 62,466
  • 11
  • 102
  • 153
  • And what is the *term* you use to describe this inability to `affect the list contents this way`? – yurisich Mar 20 '12 at 15:37
  • 2
    @Droogans, having pondered this more and read Karl's post more carefully, the answer is right there: "reference semantics." – senderle Mar 20 '12 at 15:46
  • 1
    @senderle Surely "strict reference semantics" - evaluation plays a part here also. – Marcin Mar 20 '12 at 15:57
  • 1
    I don't give it a term because it's how things are expected to work. Ability to affect the list contents is surprising, and only occurs in cases where `x` is mutated while simultaneously being a list element - something that takes care to arrange in any language and is ordinary once arranged, since mutating a list element obviously mutates a list element. Trying to look for a term for this reflects a wrong way of thinking about the situation. – Karl Knechtel Mar 20 '12 at 16:01
  • 1
    But I think @Marcin is right, actually; there are languages that do use a "pass-by-name" scheme, which could indeed result in the value of `l[0]` changing here `x = 5; l = [x]; x = 6`. I think that's probably the wrong way to do things; but the right way to do things still needs a name in this case. – senderle Mar 20 '12 at 16:08
4

I would call it "immutability" of the contained object.

I think you compare your situation with the following one:

x = []
l = [x]
x += [1]
print l # --> [[1]]

The difference is:

In this situation (the mutable situation), you mutate your original object x which is contained in the list l.

In your situation however, you have x point to an immutable object (5), which is then added to the list. Afterwards, this reference is replaced by the one to 6, but only for x, not for the list.

So x += <something> either modifies x or replaces it with another object depending on the nature of the object type.


EDIT: It as well has nothing to do with the nature of lists. You can achieve the same with 2 variables:

x = 5
y = x
print x, y, x is y
x += 1
print x, y, x is y

vs.

x = []
y = x
print x, y, x is y
x += [1]
print x, y, x is y

The first one will change x due to the immutability of ints, resulting to x is y being false, while in the second one, x is y remains true because the object (the list) is mutated and the identity of the object referenced to by x and y stays the same.

glglgl
  • 89,107
  • 13
  • 149
  • 217
  • I was thinking along the lines of pass-by-value vs pass-by-reference, but I think you nailed it. +1! – Mizipzor Mar 20 '12 at 15:26
  • 3
    The list does not make either `x` or the object in `x` immutable; in fact the object in `x` is an integer which is already immutable. The list itself is also mutable. Accordingly, I would say that "immutability" is probably the worst possible way to describe what is going on. – Marcin Mar 20 '12 at 15:31
  • 2
    @Marcin, I agree that the concept of immutability is orthogonal to the concept of "reference," which is really at the heart of this question I think. – senderle Mar 20 '12 at 15:35
  • @Marcin The OP asked why `l` is not changed if `x` is changed. The answer is that `x` isn't changed because it cannot be - thus the `+=` operation changes the object `x` points to. It is due to the __immutability__ of integers. Would it be a mutable object, `+=` would alter the object itself, leading to modified `l` - as it is in my example. What is wrong with this? – glglgl Mar 20 '12 at 16:07
  • @glglgl First of all, it is not *something that the list is doing*, as per the question; secondly, mutability is not the main aspect of this, but rather how values are held in variables, and how python evaluate expressions. – Marcin Mar 20 '12 at 16:16
  • 1
    @glglgl, I think the problem is that the behavior of `+=` in that case is actually a special case, rather than a consistent feature of the language. `x += y` _ought_ to be identical to `x = x + y`, but in the case of lists, it is not. – senderle Mar 20 '12 at 16:17
  • @senderle I am not sure about _ought_ to be - it can expected to be at the first glance, yes. Nevertheless, its semantics is "do that operation keeping the same object if possible and changing the object otherwise". It can lead to unexpected results, granted. – glglgl Mar 20 '12 at 20:20
  • @Marcin I know that it is not the list doing that. I never clained this. And mutability is in any case one aspect of this. But mutability is the main aspect of the "in place operators'" behaviour: they try to modify the given object if possible; if not, a different object is used. And the behaviour observed by the OP will only occur on immutable objects - the list keeps the old object, while the variable keeps the new one -, while mutable objects are mutated and there is no "old" or "new" object - `x` and `l` still hold the same one. – glglgl Mar 20 '12 at 20:24
1

The only thing list is doing to x in your example is reading it; it interacts with the variable in no other way. In fact the list generated by the expression [x] does not interact with the variable x at all.

If you had to introduce a piece of jargon for it, it would be value-capture, or perhaps simply independence.

I think the reason why there isn't a special term for this is that it is (a) not something that requires much discussion (b) is an aspect of strict by-value semantics where variables always hold references. Those kinds of semantics are pretty much the norm now (except where it is by reference with variables actually naming bits of memory containing objects). I think OP was expecting by-name or lazy semantics.

Marcin
  • 48,559
  • 18
  • 128
  • 201
  • Independence has a nice ring to it. Why isn't there a common name for this paradigm of python? – yurisich Mar 20 '12 at 15:39
  • @Droogans I'm not sure what you mean. This isn't something specific to python. I think the reason why there isn't a special term for this is that it is (a) not something that requires much discussion (b) is an aspect of by-value semantics where variables always hold references. I think perhaps you were expecting-by name or lazy semantics? – Marcin Mar 20 '12 at 15:46
1

The behavior you're describing has to do with references. If you're familiar with c, you're probably also familiar with "pointers." Pointers in c can get really complicated, and Python uses a data model that greatly simplifies things. But having a bit of background in c helps understand Python's behavior here, which is closely related to the behavior of c pointers. So "pointer," "reference," and "dereference" are all terms that are related to what you're talking about, although none of them is quite a "name" for it. Perhaps the best name for it is "indirection" -- though that's a bit too abstract and inclusive; this is a very specific kind of indirection. Perhaps "reference semantics"? Here's a slide from a talk by GvR himself that uses that term, and a google search turns up a few useful hits.

But if you don't have any background in c, here's my best explanation. In short, you can think of a Python name as a pointer to an object. So when you assign a name to a value, you're "pointing" that name at the value. Then, when you assign a new value to the name, you point it at a new value; but the old value isn't changed at all as a result. This seems natural when thinking about names as pointers here; the "value of the name" is changed, but the "value of the value" is not.

The thing that's a bit confusing is that += behaves inconsistently. When you use += on a number, the result makes perfect sense using the above metaphor:

x = 5
y = x
x += 1
print x, y 
# 6 5

The behavior is exactly the same as it would be if you did x = x + 1.

But sometimes += is overloaded in a way that does in-place mutation. It's a pragmatic, but slightly inconsistent, idiom:

x = [5]
y = x
x += [6]
print x, y
# [5, 6] [5, 6]

So here, the "value of the value" is changed. This is actually not my favorite thing about Python, but there are good reasons for it.

senderle
  • 145,869
  • 36
  • 209
  • 233
  • 1
    One note on "reference semantics" - although in isolation that might seem the most appropriate term, python uses call-by-value semantics, not call-by-reference, where the value passed is the reference, so to describe this as "reference semantics" might be confusing. OTOH, my preferred way of describing what is going on needs some unpacking. – Marcin Mar 20 '12 at 16:31
  • 1
    @Marcin, I appreciate your point; but I'll leave your comment as a footnote. The appropriate term to describe Python's calling convention is the subject of [perennial](http://stackoverflow.com/questions/534375/passing-values-in-python) [debate](http://stackoverflow.com/questions/986006/python-how-do-i-pass-a-variable-by-reference), generating many neologisms ([call-by-sharing](http://stackoverflow.com/a/534383/577088) (see comment), [call-by-object](http://stackoverflow.com/a/986495/577088)) and much controversy. I think "reference semantics" sums it all up well enough to get on with things. – senderle Mar 20 '12 at 16:42
  • 1
    @Marcin, or "strict reference semantics" as you suggest -- but again, that's practically a neologism too, at least judging from the very low number of [google hits](https://www.google.com/search?q="strict+reference+semantics"). – senderle Mar 20 '12 at 16:46
  • I quite agree that my comment should remain a footnote. However, call-by-reference and call-by-value have well-know, well-defined meanings, and call-by-value (of values which are references) is exactly what is going on, and is the same calling convention used in Java, (as far as I know) C#, javascript, and pretty much every other modern strict, (mostly) imperative object-oriented language. – Marcin Mar 20 '12 at 16:49
  • http://www.python.org/doc/essays/ppt/acm-ws/sld039.htm came up in that google search you linked to. – yurisich Apr 03 '12 at 13:32
0

What you're effectively doing is constructing a list with one element that references the same object as x. Then you bind a new value to x while the list still references the old element. This is because += returns a reference to a new object (6) and leaves the old 5 object intact. Integers are immutable in Python.

hochl
  • 12,524
  • 10
  • 53
  • 87