Reference or Value?

Gabriel Genellina gagsl-py2 at yahoo.com.ar
Mon Feb 23 03:03:54 EST 2009


En Mon, 23 Feb 2009 03:54:16 -0200, Denis Kasak <denis.kasak at gmail.com>  
escribió:

> On Mon, Feb 23, 2009 at 5:09 AM, Steven D'Aprano
> <steven at remove.this.cybersource.com.au> wrote:
>> On Sun, 22 Feb 2009 13:37:27 -0300, andrew cooke wrote:
>>
>>> as far as i understand things, the best model is:
>>>
>>> 1 - everything is an object
>>> 2 - everything is passed by reference
>>
>> Except that is wrong. If it were true, you could do this:
>>
>> def swap(x, y):
>>    y, x = x, y
>>
>> a = 1
>> b = 2
>> swap(a, b)
>> assert a == 2 and b == 1
>>
>>
>> but you can't, it does not work. Ergo, parameter passing in Python does
>> not have the same semantics as languages that use pass-by-reference,  
>> such
>> as Pascal and Basic. That means that even if you can justify the claim
>> "Python is pass-by-reference" by some technical argument (and I don't
>> believe you can), it is misleading to make that claim without further
>> qualifications.
>
> You could, however, argue that the swap function doesn't work as
> expected (e.g. from a Pascal or a C++ POV) simply because the
> underlying objects aren't mutable.

That's irrelevant - mutable and immutable objects are passed exactly the  
same way.

> The objects *do* get passed by
> reference; the function doesn't receive a new copy of the object and
> it can examine the original object's ID. The actual culprit is not the
> way objects are passed but the assignment operator, since it works by
> rebinding names (as Andrew Koenig explained) and not by changing the
> object itself.

There is *no* difference between "the way objects are passed" and "the  
assignment opera[tion]": both work exactly the same way.

Python execution model is based on namespaces (a collection of  
name->object pairs, usually implemented as dictionaries). An assignment x  
= y means:

  - evaluate the right hand side and obtain a value (an object, always). In  
this case, it is the object referenced by the name "y"
  - make the name "x" refer to such object. That's all.

In short, assignment rebinds a name in a namespace.
When a function call is made, a new namespace is created. The names come  
 from the function parameters (the names that were used to define the  
function in the def ... line) and the objects come from the actual  
arguments (the objects you pass inside the (...) when doing the call). The  
function code is then executed using this namespace as its locals().

def foo(a, b):
   print a, b

foo(4, ['hello', 'world!'])

The call is equivalent to:
   ns = {}
   ns['a'], ns['b'] = 4, ['hello', 'world!']
   execute foo code using ns as locals

except the right hand side is evaluated on the *calling* namespace, and  
the left hand assignments are done on the new namespace. So a call binds  
many names in a new namespace: the same as assignment.

No copies, no pointers, nothing: only names and objects are manipulated.

> If the swap() function could somehow access the
> underlying integer object and modify it, swapping of values would
> indeed occur because the function *did* get references to the objects
> passed to it.

There is a difference between modify the value of an object, and modify  
the caller's namespace. Usually "pass by reference" means that the  
*caller* may see a different thing after the call - this is not true in  
Python, there is no way the called code could alter the caller namespace  
(well, not just due to the call operation alone...)

> That said, it's a rather convoluted way of explaining what happens and
> calling it pass-by-object feels much better. :-)

And is more correct...

-- 
Gabriel Genellina




More information about the Python-list mailing list