0

I've been trying to get my head around Python's passing mechanism - pass by object reference. I often find that writing up my own understanding in a narrative fashion is a useful excercise, but think it is only partly correct. Comments and corrections would be most welcome.


In Python, function arguments are passed by value. And that's why you can't change the value of a passed integer: a copy of the integer is made, and you can only alter the copy, not the original.

But you say, if that's true, why am I able to append to a list that's passed into a function? If it's passed by value, then the function should be operating on a copy of the list!

And the answer to that is - and it's a mouthful - the value that's passed is a copy of the variable that contains a reference to your list object. Object references are passed by value.

Say you have myList = [1, 2]. Think of the = as a divider. On the left we have a variable, myList. On the right we have the [1, 2] list itself, somewhere in memory. The variable contains a reference to the thing on the right – its location in memory. When you access the list, you unpack the contents of the variable to retrieve the contained reference, and it's the reference - the object's address - that you use to access the list itself. So, when you pass myList to a function, you're passing a copy of the variable – which is a container for the reference really. Of course, as it was passed by value, the copy contains the same reference, so you can also access the list in your function. In this situation you had two variables, the original and the one you received in the function; each containing the same value – the reference.

So what happens in the integer scenario that makes it different?

In Python, integers aren't exactly like the objects we talk about in Object Oriented Programming; really, we can regard them as just blobs of data, with none of the properties we associate with objects in our OO world: they're not instantiated in the same way as an object defined in a class ; they have no self-reference; and they cannot have functional attributes (methods). So it's perhaps too easy, and arguably wrong, to talk about integer objects in Python. In any case, it's certainly confusing things semantically!

So what is a Python integer? Well, if you have a C background, you'll know all about the 'struct'; which is exactly how integers are manifested in Python:

typedef struct { PyObject_HEAD long ob_ival; } PyIntObject;

And, if you have no C (or C-derivative background), you can more-or-less consider integers to be pieces of integer-sized memory directly (ignoring PyObject).

Now, remember once again, that Python uses pass-by-value, so when passing an integer, you're passing a copy of a 'struct' - or a piece of memory - that contains the integer's actual value (it is in ob_ival), and not something that contains a reference to something somewhere else in memory. Now, when you assign a value to an integer that's passed to a function, you're altering your own private copy of ob_ival, and not the original.

peedurrr
  • 187
  • 16
  • 2
    *"Python uses pass-by-value"* - no, Python passes by assignment. You can't change the original integer because *integers are immutable*. – jonrsharpe Oct 15 '14 at 10:13
  • 1
    See also http://www.jeffknupp.com/blog/2012/11/13/is-python-callbyvalue-or-callbyreference-neither/ – Tim Pietzcker Oct 15 '14 at 10:15
  • 1
    *"integers... cannot have functional attributes"* - also false, `int.bit_length` exists, for example. You absolutely can *"talk about integer objects in Python"* - they do exist, and are just like lists (although more like tuples, which are also immutable). Everything in Python (integers, lists, classes, instances, functions, modules, ...) is an object, they all just have different properties. – jonrsharpe Oct 15 '14 at 10:18
  • @jonrsharpe so this article is wrong too - http://robertheaton.com/2014/02/09/pythons-pass-by-object-reference-as-explained-by-philip-k-dick/ – peedurrr Oct 15 '14 at 10:53
  • @jonrsharpe yes, I did notice that bit_length() etc were invokable on an integer, but thought they were more smoke and mirrors vs what one might call the 'real thing'. – peedurrr Oct 15 '14 at 10:55
  • @peedurrr no, that article is correct, "pass-by-object-reference" is another way of saying "pass-by-assignment" (I use the latter as I think it's clearer that this is separate to "pass-by-reference"). Have a read through http://nedbatchelder.com/text/names.html, which explains how Python's object references (usually referred to as *names*) work. – jonrsharpe Oct 15 '14 at 10:55
  • Thinking about Python objects in C terms can be helpful, but it can also be confusing. :) IMHO, it's better to think about Python entities in their own terms and not worry too much about what's happening under the hood, at least until the Python way of thinking becomes second nature. (FWIW, I was writing in C for over 20 years before I started on Python, so I think I know where you're coming from). I _was_ going to post a link to the Ned Batchelder article, but Jon's beat me to it. :) – PM 2Ring Oct 15 '14 at 11:01
  • @jonrsharpe: your "pass-by-assignment" is just pass-by-value. – newacct Oct 15 '14 at 18:44
  • @newacct no, "pass-by-value" means passing a *copy* to the function which (as you can see with mutable objects) is *not* what happens. See the various questions/articles already linked to this one. – jonrsharpe Oct 15 '14 at 18:46
  • @jonrsharpe: You are mistaken. "Objects" are not values in Python. All values in Python are references (pointers to objects). Therefore it is not possible to "pass an object" in Python. You pass pointers, by value (they are copied). The semantics of passing and assigning in Python are *exactly identical* to that in Java, and Java is universally described as pass-by-value. A term must be used consistently across languages. – newacct Oct 15 '14 at 18:54
  • @newacct Java, to quote [this answer](http://stackoverflow.com/a/40523/3001761) *"passes references by value"*, which is indeed what Python does. However, that is subtly different from what is referred to as "pass-by-value" in other languages (e.g. .NET) - specifically, it allows changes in the called function to leak out. Python doesn't have Java's primitives (which *are* passed by value), either; everything is an object. Anyway, [the docs say assignment](https://docs.python.org/3/faq/programming.html#how-do-i-write-a-function-with-output-parameters-call-by-reference) and I'm sticking to it. – jonrsharpe Oct 15 '14 at 19:00

0 Answers0