6

Since Python doesn't have pointers, I am wondering how I can pass a reference to an object through to a function instead of copying the entire object. This is a very contrived example, but say I am writing a function like this:

def some_function(x):
    c = x/2 + 47
    return c

y = 4
z = 12

print some_function(y)
print some_function(z)

From my understanding, when I call some_function(y), Python allocates new space to store the argument value, then erases this data once the function has returned c and it's no longer needed. Since I am not actually altering the argument within some_function, how can I simply reference y from within the function instead of copying y when I pass it through? In this case it doesn't matter much, but if y was very large (say a giant matrix), copying it could eat up some significant time and space.

Torxed
  • 22,866
  • 14
  • 82
  • 131
hannah
  • 889
  • 4
  • 13
  • 27
  • 1
    Docs: [How do I write a function with output parameters (call by reference)?](http://docs.python.org/2/faq/programming.html#how-do-i-write-a-function-with-output-parameters-call-by-reference) – Ashwini Chaudhary Mar 21 '14 at 12:31

2 Answers2

16

Your understanding is, unfortunately, completely wrong. Python does not copy the value, nor does it allocate space for a new one. It passes a value which is itself a reference to the object. If you modify that object (rather than rebinding its name), then the original will be modified.

Edit

I wish you would stop worrying about memory allocation: Python is not C++, almost all of the time you don't need to think about memory.

It's easier to demonstrate rebinding via the use of something like a list:

def my_func(foo):
    foo.append(3)  # now the source list also has the number 3
    foo = [3]      # we've re-bound 'foo' to something else, severing the relationship
    foo.append(4)  # the source list is unaffected
    return foo


original = [1, 2]
new = my_func(original)

print original     # [1, 2, 3]
print new          # [3, 4]

It might help if you think in terms of names rather than variables: inside the function, the name "foo" starts off being a reference to the original list, but then we change that name to point to a new, different list.

Daniel Roseman
  • 588,541
  • 66
  • 880
  • 895
  • I am beginning to understand this better, but what do you mean by "rebinding its name"? Do you mean if x were an argument of some_function(x), and I were to say within the function x = x+2 ? And this would result in new memory allocation, correct? – hannah Mar 21 '14 at 12:57
2

Python parameters are always "references".

The way parameters in Python works and the way they are explained on the docs can be confusing and misleading to newcomers to the languages, specially if you have a background on other languages which allows you to choose between "pass by value" and "pass by reference".

In Python terms, a "reference" is just a pointer with some more metadata to help the garbage collector do its job. And every variable and every parameter are always "references".

So, internally, Python pass a "pointer" to each parameter. You can easily see this in this example:

>>> def f(L):
...     L.append(3)
... 
>>> X = []
>>> f(X)
>>> X
[3]

The variable X points to a list, and the parameter L is a copy of the "pointer" of the list, and not a copy of the list itself.

Take care to note that this is not the same as "pass-by-reference" as C++ with the & qualifier, or pascal with the var qualifier.

vz0
  • 32,345
  • 7
  • 44
  • 77
  • I've had occations where this fails tho. Mainly when working with classes and threads. – Torxed Mar 21 '14 at 12:46
  • @Torxed This should never fail, as this is how Python works, always. If you are using threads I am guessing that the most possible cause for your coding issues are threading ones. – vz0 Mar 21 '14 at 12:47
  • Might be, was a while since it happened.. – Torxed Mar 21 '14 at 12:51
  • @vz0 I take this to mean that I am actually not copying the data from y or z into my function--I am just passing a "pointer". The only time in which Python allocates new memory would be if I mutated y or z \emph{within} some_function. So as long as I do not mutate it within the function, I am not slowing down my program. – hannah Mar 21 '14 at 12:52
  • @hannah That's correct. Edited my answer a little – vz0 Mar 21 '14 at 13:00