By value or by reference?

R

Riccardo Rossi

Hi all!

How does Python pass arguments to a function? By value or by reference?

Thanks,
Riccardo Rossi.
 
J

Jorge Godoy

Riccardo Rossi said:
Hi all!

How does Python pass arguments to a function? By value or by reference?

IIRC, by reference. It uses a copy on write algorithm.
 
R

Roger Irwin

Riccardo said:
Hi all!

How does Python pass arguments to a function? By value or by reference?

Thanks,
Riccardo Rossi.
By reference to an object....See the python tutorial.
 
J

Jonathan Ellis

Roger said:
By reference to an object....See the python tutorial.

Wrong. Here is the difference between pass by reference and pass by
value to CS types:

With pass-by-reference, i would now be 1. However, since python is
pass-by-value, it remains 10.

-Jonathan
 
A

Alex Martelli

Jonathan Ellis said:
Wrong. Here is the difference between pass by reference and pass by
value to CS types:


With pass-by-reference, i would now be 1. However, since python is
pass-by-value, it remains 10.

....so you tell "CS types" it's pass-by-value, and they come right back
with

def bar(b): b.append(2)

z = []
bar(z)
print z

With pass-by-value, they'll say, z would still be []. However, since
what is passed is not just (a copy of) the value, but (a reference to)
the object itself, z is [2] instead.

The terminology problem may be due to the fact that, in python, the
value of a name is a reference to an object. So, you always pass the
value (no implicity copying), and that value is always a reference.

I find it simpler to explain as: the semantics of argument passing are
_exactly_ identical to that of assignment (binding) to a barename; you
can fruitfully see argument passing as local (bare) names of the called
function being assigned initial values by the caller (that's exactly
what happens, in practice). Now if you want to coin a name for that,
such as "by object reference", "by uncopied value", or whatever, be my
guest. Trying to reuse terminology that is more generally applied to
languages where "variables are boxes" to a language where "variables are
post-it tags" is, IMHO, more likely to confuse than to help.


Alex
 
O

Oliver Fromme

Jonathan said:
>
> Wrong. Here is the difference between pass by reference and pass by
> value to CS types:
>
>
> With pass-by-reference, i would now be 1. However, since python is
> pass-by-value, it remains 10.

It remains 10 because integers are immutable, so the function
code cannot modify the caller's variable anyway. However, if
you pass a mutable variable, things look a little different:
def foo(a): a[0] = 1 ....
i = [10]
foo(i)
print i
[1]

Best regards
Oliver
 
B

Bruno Desthuilliers

Riccardo said:
Hi all!

How does Python pass arguments to a function? By value or by reference?

Both...
Err, no, none.
Well...

*Short answer :*
args are passed by ref, but bindings are local.

*Long answer :*
You first need to understand what 'variables' in Python are. They are in
fact just a symbol referencing an object. Think of a Python 'variable'
as an entry in a dict, the name of the variable (the 'symbol') being the
key and the reference to the object being the value (AFAIK, this is
exactly what they are).

You also need to understand the difference between mutable and immutable
objects. Strings, numerics and tuples are immutables. Which means that
you can not change them. When doing :
s = "Hello "
s += "World"
.... you are not modifying the string object bound to s, but creating a
new string object and binding it to s.

Now for the "By Val/By Ref" stuff... well, try this :

def my_fun(my_arg):
print "in my_fun, before rebinding my_arg: my_arg = %s" % my_arg
my_arg = "42"
print "in my_fun, after rebinding my_arg: my_arg = %s" % my_arg

the_arg = "Life, the Universe, and Everything"

print "before call to my_fun: the_arg = %s" % the_arg
my_fun(the_arg)
print "after call to my_fun: the_arg = %s" % the_arg


You should have somthing like this :

before call to my_fun: the_arg = Life, the Universe, and Everything
in my_fun, before rebinding my_arg: my_arg = Life, the Universe, and
Everything
in my_fun, after rebinding my_arg: my_arg = 42
after call to my_fun: the_arg = Life, the Universe, and Everything

So what ? are we passing args by value ? Well, retry with :

def my_fun_2(my_arg_2):
print "in my_fun, before appending to my_arg_2: my_arg_2 = %s" %
my_arg_2
my_arg_2.append("42")
print "in my_fun, after appending to my_arg_2: my_arg_2 = %s" %
my_arg_2

the_arg_2 = ["Life, the Universe, and Everything"]

print "before call to my_fun_2: the_arg_2 = %s" % the_arg_2
my_fun_2(the_arg_2)
print "after call to my_fun_2: the_arg_2 = %s" % the_arg_2

and what do we get ?

before call to my_fun_2: the_arg_2 = ['Life, the Universe, and Everything']
in my_fun, before appending to my_arg_2: my_arg_2 = ['Life, the
Universe, and Everything']
in my_fun, after appending to my_arg_2: my_arg_2 = ['Life, the Universe,
and Everything', '42']
after call to my_fun_2: the_arg_2 = ['Life, the Universe, and
Everything', '42']

Argh ! So what ? Is it by val or by ref ?
Ok, let's try a third test :

def my_fun_3(my_arg_3):
print "in my_fun, before rebinding my_arg_3: my_arg_3 = %s" % my_arg_3
my_arg_3 = ["42"]
print "in my_fun, after rebinding my_arg_3: my_arg_3 = %s" % my_arg_3

the_arg_3 = ["Life, the Universe, and Everything"]

print "before call to my_fun_3: the_arg_3 = %s" % the_arg_3
my_fun_3(the_arg_3)
print "after call to my_fun_3: the_arg_3 = %s" % the_arg_3

An you get :
before call to my_fun_3: the_arg_3 = ['Life, the Universe, and Everything']
in my_fun, before rebinding my_arg_3: my_arg_3 = ['Life, the Universe,
and Everything']
in my_fun, after rebinding my_arg_3: my_arg_3 = ['42']
after call to my_fun_3: the_arg_3 = ['Life, the Universe, and Everything']

err... Time for some explanation ?-)

When you call a function with an arg, a "local variable" is created,
which references the object passed as the argument. (well... an entry
with the formal parameter name as key and a reference to the object
passed in is created in the 'local' dict).

So, rebinding this local symbol does not impact the binding in the
caller's namespace - because the symbol lives in another namespace.

*But* - and if the object referenced is mutable of course - modifying
the object in the function... well, just modifies the object, because
it's the *same* object that is bound to ('referenced by', if you prefer)
both symbols (the one in the caller's namespace and the one in the
function's namespace). So yes, the object *is* modified when the
function returns.

(Of course, doing anything to an immutable object is just rebinding the
symbol, so it won't never have any impact outside the function. So don't
expect to have a function having side-effects on strings, numerics and
tuples args. The good news being that this is not necessary, since the
only reason to do so would be to return multiple values, and Python can
already return multiple values.)


Does it make sens to you ?-)
Thanks,
Riccardo Rossi.

HTH
Bruno

(Ho, BTW, please read the fine manual - and this too :
http://starship.python.net/crew/mwh/hacks/objectthink.html)
 
J

JCM

It remains 10 because integers are immutable, so the function
code cannot modify the caller's variable anyway. However, if
you pass a mutable variable, things look a little different:

It doesn't matter that integers are immutable. Rebinding formal
parameters cannot change variables in the callers scope.
def foo(a): a[0] = 1 ...
i = [10]
foo(i)
print i
[1]

In this case, you're dereferencing the list (I'm using pointer-
terminolgy, but I'm still talking about the behavior of the language,
not its implemenation). You're basically modifying the object passed
into the function, not rebinding a variable.
 
A

Andrew Dalke

Jorge said:
IIRC, by reference. It uses a copy on write algorithm.

Really? Where? I've heard theoretical rumblings about
that but didn't realized it had been added anywhere.

Andrew
(e-mail address removed)
 
M

Michael Hoffman

Jonathan said:
Wrong. Here is the difference between pass by reference and pass by
value to CS types:

Actually it is a reference to an object being passed.
With pass-by-reference, i would now be 1. However, since python is
pass-by-value, it remains 10.
.... print id(a)
....168377924

With pass-by-value, the memory location of a would be different than the
memory location of i. However, since Python is pass-by-reference, it
remains the same. <wink>

Alex is right that trying to shoehorn Python into a "pass-by-reference"
or "pass-by-value" paradigm is misleading and probably not very helpful.
In Python every variable assignment (even an assignment of a small
integer) is an assignment of a reference. Every function call involves
passing the values of those references.
 
J

JCM

Michael Hoffman said:
With pass-by-value, the memory location of a would be different than the
memory location of i. However, since Python is pass-by-reference, it
remains the same. <wink>

The memory location of the object is the same; the memory location of
the reference is different.
Alex is right that trying to shoehorn Python into a "pass-by-reference"
or "pass-by-value" paradigm is misleading and probably not very helpful.
In Python every variable assignment (even an assignment of a small
integer) is an assignment of a reference. Every function call involves
passing the values of those references.

I've given up expressing my opinion on the matter. Everyone here
seems to have a different notion of what "pass-by-reference" and
"pass-by-value" mean. It's funny--I've never run into trouble with
these terms before seeing these discussions on C.L.Py.
 
J

Josiah Carlson

I've given up expressing my opinion on the matter. Everyone here
seems to have a different notion of what "pass-by-reference" and
"pass-by-value" mean. It's funny--I've never run into trouble with
these terms before seeing these discussions on C.L.Py.

It is because Python does it differently from most other languages, and
it doesn't fit the paradigms of "pass by value" or "pass by reference"
as already explained by Alex Martelli.

Python does name binding with references. That is, each reference is
given a name, but you cannot change data by assigning to a name; you can
only change what data that name points to. There are certain operations
that can be done with mutable objects and immutable objects, but that is
another discussion entirely.


There is not so much an argument, but there is a semantic "what the hell
is it doing" that is not being communicated properly. I am sure there
is a FAQ about this, but I don't have the link handy, and I can't quite
find the right incantation for Google.

- Josiah
 
J

JCM

It is because Python does it differently from most other languages, and
it doesn't fit the paradigms of "pass by value" or "pass by reference"
as already explained by Alex Martelli.

It's really not that different. It's very similar to the way Java
handles objects, and how scheme does argument-passing.
Python does name binding with references. That is, each reference is
given a name, but you cannot change data by assigning to a name; you can
only change what data that name points to. There are certain operations
that can be done with mutable objects and immutable objects, but that is
another discussion entirely.

Yes. These two issues often get muddled together in discussions about
argument passing. Are you avoiding the term "variable"? Some don't
like to use it because they see Python as somehow fundamentally
different than other languages. I think the term fits nicely.
 
A

Alex Martelli

Josiah Carlson said:
It is because Python does it differently from most other languages, and

Actually, where "real objects" are concerned (there's a slew of
exceptions for primitive builtin types such as int) Java has quite
similar semantics for both assignment and parameter passing. Python's
simpler: no exceptions. C#'s more complicated: besides the types that
are built-in exceptions you can also make user-defined types that are
also exceptions. But exceptions apart, the 'fundamental' semantics of
assignments and assignment passing is similar in all three languages.


Alex
 
J

Josiah Carlson

[snip section about Java]

Indeed, I meant in reference to C, but I should have been more precise.
Yes. These two issues often get muddled together in discussions about
argument passing. Are you avoiding the term "variable"? Some don't
like to use it because they see Python as somehow fundamentally
different than other languages. I think the term fits nicely.

In my mind, "variable" implies that the data is implicitly "variable" by
assignment, which is not the case in Python.

Underlying name binding in Python is a Python dictionary; a mapping of
keys to values, where keys are names, and values are pointers to actual
data (there are optimizations for local scopes that replace the
dictionary with a static table, but one could use a dictionary and it
would work the same).

As a result, an assignment in a scope is no more than doing doing an
assignment to a key/value pair in dictionary, with similar "hey, we're
just swapping pointers on assignment, not changing the data itself" (at
least in terms of the 'value' part of the key,value pair).


In a C-semantic pass by reference, you get the pointer to the actual
data, and when you assign to that pointer, you change the data itself.
In a C-semantic pass by value, you get a value with copy on write
semantics.

If what Python does is like Java, perhaps C# or what have you, great. It
is, however, different from the C semantic description of "pass by value",
"pass by reference", and the standard CS education definition of either.

- Josiah
 
D

Donn Cave

Andrew Dalke said:
Really? Where? I've heard theoretical rumblings about
that but didn't realized it had been added anywhere.

I think this is a misimpression - the copy on write
part, I mean - that may go back to a discussion that
took place a year ago here, where someone energetically
but erroneously advocated that point of view.

Donn Cave, (e-mail address removed)
 
D

Donn Cave

Bruno Desthuilliers said:
*Short answer :*
args are passed by ref, but bindings are local.

*Long answer :*
You first need to understand what 'variables' in Python are. They are in
fact just a symbol referencing an object. Think of a Python 'variable'
as an entry in a dict, the name of the variable (the 'symbol') being the
key and the reference to the object being the value (AFAIK, this is
exactly what they are).

You also need to understand the difference between mutable and immutable
objects. Strings, numerics and tuples are immutables. Which means that
you can not change them. When doing :
s = "Hello "
s += "World"
... you are not modifying the string object bound to s, but creating a
new string object and binding it to s.

Well, true enough for string, but not true for list for example.

Aside from this wretched wart on the language, as another followup
has already pointed out, you really don't need to distinguish
mutable vs. immutable to understand argument passing and variable
binding in Python.

If you write:
def f(a, b):
a = 5
b.flog(5)

.... it makes no difference whether either argument is mutable
or immutable. a becomes a different object notwithstanding,
and b.flog operates on the caller's original object whether flog
modifies anything or not. We tend to make this too complicated.

Donn Cave, (e-mail address removed)
 
A

Alex Martelli

Josiah Carlson said:
If what Python does is like Java, perhaps C# or what have you, great. It
is, however, different from the C semantic description of "pass by value",
"pass by reference", and the standard CS education definition of either.

C is also very simple, just like Python: C always does pass by value.
I.e., C always does implicit copy (on assignment or parameter passing),
just like Python never does.

So in C you ask explicitly when you want a reference (pointer) instead,
e.g. with &foo -- in Python you ask explicitly when you want a copy
instead, e.g. with copy.copy(foo). Two simple language, at opposite
ends of the semantics scale, but each consistent and clean. (Python
matches 4.5 of the 5 points which define "the spirit of C" according to
the latter's Standard's preface...!-).

[[ok, each has its warts -- e.g. C has arrays which mysteriously decay
into pointers instead of getting copied, Python has slices that make
copies instead of sharing part of the original sequence [or not; it
depends whether said sequence is a list or Numeric.array, sigh...] --
being human and being perfect are incompatible traits. But _mostly_
they have simplicity and consistency, everything explicit.]]

The key point is that, in both languages, a function's arguments are
just like local variables pre-initialized by the caller with assignment
statements. In both languages, if the function reassigns an argument
it's just playing with its own local variables, the caller is never in
any way affected by that. In both languages, there are other ways
except plain barename assignments to possibly "affect the caller" (in C
you basically need to have been passed a pointer, and dereference that
pointer or another pointer computed from the first by pointer
arithmetic; in Python you basically need to have been passed a mutable
object, and call mutating methods on that object). Again, in both cases
I see simplicity and consistency, everything pretty explicit...


Alex
 
J

Josiah Carlson

The key point is that, in both languages, a function's arguments are
just like local variables pre-initialized by the caller with assignment
statements. In both languages, if the function reassigns an argument
it's just playing with its own local variables, the caller is never in
any way affected by that. In both languages, there are other ways
except plain barename assignments to possibly "affect the caller" (in C
you basically need to have been passed a pointer, and dereference that
pointer or another pointer computed from the first by pointer
arithmetic; in Python you basically need to have been passed a mutable
object, and call mutating methods on that object). Again, in both cases
I see simplicity and consistency, everything pretty explicit...

I agree with most everything you have said, though consider the pointer
vs. value of C to define the semantics of the passing. That is, if you
get a pointer in C, it is by reference. If you don't get a pointer, it
is by value.

I also agree that everything is pure and explicit in both languages, it
took me a few minutes mucking around with the interpreter my first time
to understand how Python deals with the base types.

I'm trying to point out that if you toss the standard C semantic
definition of "pass by value" and "pass by reference", by merely
pretending that the definitions have not been given in the history of
computer science, and just look at how Python does actual name binding
in namespaces/scopes, you can understand what Python does much better
than to get into a "Python does pass by reference" vs. "Python does pass
by value" argument.


- Josiah
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
474,209
Messages
2,571,088
Members
47,687
Latest member
IngridXxj

Latest Threads

Top