Finding the instance reference of an object

Steven D'Aprano steven at REMOVE.THIS.cybersource.com.au
Tue Nov 11 01:14:01 EST 2008


On Tue, 11 Nov 2008 16:54:10 +1300, greg wrote:

> Steven D'Aprano wrote:
> 
>> But the name isn't the argument. The argument to a function is an
>> object
> 
> The *formal* argument *is* a name, and that's what the phrase "changes
> to the arguments within the called procedure" is talking about.

If you equate "arguments within the called procedure" to the *name* of 
the arguments, then changing the arguments would mean changing the NAME, 
not the object bound to the name. That is, something like this:

def foo(x):
    y = x
    del x

except as a single operation. I'm sure that's not what you intended to 
say, but that's what you have said. Except for del and rebinding, Python 
level code does not allow you to do anything to *names*, only to objects. 
But I'm sure you know this, which makes your claim all the more confused.


>> Take a function foo that takes one formal parameter x. Pass an actual
>> argument y to it. The argument is the object currently bound to y, not
>> the name y. Nothing inside foo can rebind the name y because foo
>> doesn't see the name y, it sees the object.
> 
> More to the point, it sees the *name x* rather than the name y, and
> rebinding the name x doesn't change the binding of name y. Therefore,
> the name y has been passed by value, not by reference.

The term for what you have just said is "non sequitor", Latin for "it 
does not follow". The _name_ y is not passed AT ALL. If there is a value 
that is passed, it is the object bound to y, and not any name at all.

If you equate "value" with "object", as you suggested some posts ago, 
then it could be argued that Python is call-by-value (for value=object) 
but because "call by value" has connotations and implications that do not 
apply to Python, we prefer to avoid the misleading and confusing term 
c-b-v in preference to Barbara Liskov's term "call by sharing" or "call 
by object".

At least some sections of the Java community seem to prefer a misleading 
and confusing use of the word "value" over clarity and simplicity, but I 
for one do not agree with them.

 

>> [1] You can pass a string representing the name to a function, which
>> can then use some combination of setattr, globals(), exec etc to work
>> with the name represented by that string.
> 
> This would be the Python equivalent of the strategy used in C to emulate
> call-by-reference -- and it's needed for the same reason, i.e. the
> language itself only provides call-by-value. So you pass a value that
> you can manually dereference to get the same effect.

In the general case, you can't emulate call-by-reference by passing a 
name, because you don't know what the name of an object is. Obviously I 
can hard-code some names:

def swap(x, y):
    # arguments x and y are actually pointless
    g = globals()
    g['x'], g['y'] = g['y'], g['x']


but you can't emulate c-b-r's ability to swap arbitrary names determined 
by the compiler. The reason is that when you call a function with an 
argument, the function sees only the object, and the object does not know 
what name(s) is bound to it.


You could do this:

def swap(x_name, y_name):
    g = globals()
    g[x_name], g[y_name] = g[y_name], g[x_name]

which gives you something a little closer to c-b-r, but it still isn't 
the same thing. Some major differences:

- you can't affect values unless they are bound to a name, that is no 
swapping of anonymous values, e.g. swap(a[4], a[8]) could not work;

- within a nested scope, you can't affect anything unless it is in the 
global scope;

- you need to know the name to apply at runtime, there is no way to 
programmatically discover it. 

The third point is the most telling. Consider the Pascal procedure:

procedure swap(var x, var y: integer):
  var tmp: integer;
  begin
    tmp := x;
    x := y;
    y := tmp;
  end;


Given two integer variables a and b, you call the procedure swap(a, b), 
and the compiler can determine what memory addresses are used. If Pascal 
was like Python, you would have to determine the addresses yourself:

a := 1;
b := 2;
swap(12693024, 190342874);

after which a would equal 2 and b would equal 1. Obviously Pascal is not 
like that, but Python is (using names instead of memory locations). This 
proves that Python names are nothing like Pascal call-by-reference 
arguments. Passing a name is *not* Python's way to emulate call-by-
reference.


-- 
Steven



More information about the Python-list mailing list