Python is not call-by-reference. If it were, we would expect 2 to be printed below, but it is not:
>>> def f(x):
... x = 2
>>> x = 1
>>> f(x)
>>> x
1
One might refer to r as being referentially transparent, or immutable (I don't know if it is--I am assuming). I would refer to python as using uniform reference semantics - http://metamodular.com/common-lisp-semantics.html
What does that Python mean, by the way? The passing of the value into the function is clear enough, but I have no idea whether f is assigning to the local x, or binding a new one.
If we capture a lambda before "x = 2", and then call it afterward, does it see an x which holds the original argument value or which holds 2?
In Lisps, this stuff is clear. Mostly. Except Common Lisp has some areas where it waffles: in some iteration constructs, implementations can bind a new variable or reuse the same one. Those choices are individually clear, though.
Holy fuck, I simply cannot just cut and paste the above into Python as-is, because of the "unexpected indent" which I added so that HN shows that as quote. It's complaining about an unexpected indent.
Kill. Me. Now.
Anywway:
>>> def f(x):
... g = lambda : x
... x = 2
... return g()
...
>>> f(42)
2
So what it looks like is that there is only one x in the function, established by the parameter. This x is captured by the lambda, and is then reassigned the value 2. The lambda retrieves the 2.
For completeness we show that if x is not assignmed, g accesses f's argument value:
>>> def f(x):
... g = lambda : x
... return g()
...
>>> f(42)
42
If it's 3 then it's pass by reference here, if it's 10 it's pass by reference. Which is it?
Additionally, for something to be a closure it has to close over something (an environment). What does `f` or `g` close over? Note that they aren't changing any environment, they are "merely" functions, not closures. Python does have closures, but those aren't examples of them.
And being able to assign a function to a variable does not make a closure, or do you think that C has closures because it has function pointers?
No need to change your entire mind; just an incorrect definition of call-by-reference.
Passing a value which has reference semantics isn't call-by-reference.
Your f receives x by value. That value is a reference into a boxed object. The x[0] = 1 does not change x; it changes the boxed object.
>>> def f(x):
... x[0] = 1
...
>>> a = [ 0, 2, 3 ]
>>> b = a
>>> f(a)
>>> a is b
True
The f function can do nothing to make "a is b" false.
Under pass-by-reference, assigning to x would do that.
Under pass-by-reference, we can pass a reference to a, such that a can be replaced, without affecting b.
"pass-by {whatever}" refers to the semantics of the parameter and what it receives from the argument expression, and how, not the semantics of the argument object/value.
I don't expect 2 to be printed. I think you're conflating scope with calling conventions. x is locally scoped to the function. `f` behaves like a lambda/closure.
Would you expect `(define f (lambda(x) x))` to have awareness about some global `x`? The only difference with Python is that the closure has access to the global scope unless the variable is locally defined and a new reference is created in the frame.
Nope, that code actually does demonstrate the difference between pass by reference and pass by value. If you prefer, change either the `x`'s in the function to be `y` or the global `x`'s to by `y` and you'll see the same behavior. Which shows that Python is not, in fact, pass by reference.
I think I see what you are saying (the shared variable threw me), but it STILL isn't doing what you think.
def s(x):
x[1] = 2222
return x
x = [1,2,3]
print(s(x)) # prints [1, 2222, 3)
As you can see, it is pass by reference.
Tuples, strings, numbers, and some other things are immutable.
When you pass them, you pass a reference (from the user's perspective as this can be optimized to pass by value as the interpreter sees fit). When you update that reference, because they are immutable, you must update the current reference to a new location in memory. Because you are changing what the new pointer variable in the function points to, of course the other pointer doesn't update.
No, it's passing a reference, but it is still not pass by reference, this is actually worth distinguishing because they are different behaviors. That function (by moonchild) does exactly what moonchild meant it to do, which was to demonstrate that Python is not pass by reference. Another function demonstrating that Python is not pass by reference:
def swap(a, b):
a, b = b, a
a = [1,2]
b = [3,4]
print(a,b)
swap(a,b)
print(a,b)
If Python were pass by reference (versus passing a reference in these cases) then it would perform a swap, but it does not perform a swap because it is not pass by reference. C++ has pass by reference (as an option), as do Pascal and Ada, and more languages. But Python is not among them. An actual pass-by-reference swap, in C++:
template<typename T> // template to be the most equivalent to the intended Python code
void swap(T& a, T& b) {
T t = a;
a = b;
b = a;
}
That will actually perform a swap when called with `swap(x,y)`. Any language that offers (by option or by default) pass by reference can have an equivalent swap function, including a generic one like the above if the language offers some notion of generics or is dynamically typed (like Python).
Yes, pointer’s are themselves passed by value (no pointers to pointers) due to garbage collection where the ability to directly alter them would cause crashes (like basically every C++ program does if you spend enough time fuzzing it).
That doesn’t change the fact that they are indeed pointers (aka references).
How are pointers to pointers passed? You don’t want to reference another stack frame directly, so you pass by value.