Finding the instance reference of an object [long and probably boring]

Joe Strout joe at strout.net
Fri Nov 7 13:55:21 EST 2008


On Nov 7, 2008, at 10:29 AM, Steven D'Aprano wrote:

>> Note: I tried to say "name" above instead of "variable" but I  
>> couldn't
>> bring myself to do it -- "name" seems to generic to do that job.   
>> Lots
>> of things have names that are not variables: modules have names,  
>> classes
>> have names, methods have names, and so do variables.
>
> But modules, classes and methods are also objects, and they can be  
> bound
> to names.

OK, that's a good point.  It strikes me as a generally Bad Idea to  
actually take advantage of that (i.e., to reassign to a class or  
module name), but I guess Python allows it.

> Unfortunately, the term "name" is *slightly* ambiguous in Python.  
> There
> are names, and then there are objects which have a name attribute,  
> which
> holds a string. This attribute is usually called __name__ but  
> sometimes
> it's called other things, like func_name.
>
> The __name__ attribute of objects is an arbitrary label that the  
> object
> uses for display purposes. But names are the entities that Python code
> usually uses to refer to objects.

Right.  This may lead to the confusion that started this thread, i.e.  
someone asking how to find the "name" of an arbitrary object (by which  
they meant the entry in some namespace that refers to it, what I like  
to call a variable name).  If you think of objects as "having" names  
(which as you point out is sort of true in some cases but not in  
general), rather than names as referring to objects, then you get into  
this trouble.

> You're also assuming that the use of "call-by-value" to refer to very
> different behaviours in C and Java somehow makes communication  
> easier and
> smoother. I don't think it does.

OK, so now we're getting down to it: you think that Python's behavior  
is like Java, but Java's behavior is different from C, right?

What would it take to convince you that Java and C have exactly the  
same semantics, and differ only in syntax?  Would equivalent code  
snippets that do the same thing do the job?

>> In a language that supports
>> integers and doubles as simple types, stored directly in a variable,
>> then it is an obvious generalization that in the case of an object
>> type, the value is a reference to an object.
>
> How is it a generalization?

Because you start with, say, integers, and make such observations as:

1. x = y copies the integer value from y into x.
2. foo(x), where foo's parameter is by-value, copies x into the formal  
parameter.
3. foo(x), where foo's parameter is by-reference (e.g. using & in C++,  
or using ByRef in RB/VB.NET), makes the formal parameter an alias of x.

Then you look at a declaration of (speaking loosely) object type, such  
as Java's

   SomeClass x;

or C++'s

   SomeClassPtr x;  // where typedef SomeClass* SomeClassPtr;

Then you ask, how do the above situations 1-3 apply to this?  Well,  
they apply just fine, except that what is being copied or aliased is  
the reference to an object rather than an integer.

That's the obvious generalization I was thinking of.

> Using Python syntax instead of Java, but let's pretend that Python  
> ints
> are primitives just like in Java, but floats are not. I do this to  
> avoid
> any confusion over mutable/immutable, or container types. Nice simple
> values, except one is an object and one is a primitive type.
>
> x = 1  # the value of x is 1
> x = 1.0  # the value of x is 0x34a5f0

Strictly true, but irrelevant if float objects are immutable.   
Immutable objects can be treated as values; it's only by mutating an  
object that you can tell that you're dealing with references to shared  
data.

> What dereferencing step? There's no such thing in Python code. You  
> just
> use the name, as normal.

If you just use the name, then you're accessing the reference.  To get  
to the actual data, you have to dereference it with ".".  (Granted,  
this dereferencing is often done within operator methods so that it's  
mostly hidden from you in many cases, especially when dealing with  
number- and string-like objects.)

> Oh sure, at the deep implementation level there's a dereferencing  
> step,
> but that applies for primitive types in C too. When you refer to a
> variable x in C, the CPU has to look into a memory location to find  
> out
> what the value of x is.

That's not what I'm talking about.  I'm talking about "person.age" in  
Python, Java, or .NET, or "person->age" in C/C++.

> Personally, they would have to be pretty big to make me give up saying
> that the value of x after x=1 is 1.

I've stated repeatedly that this is fine shorthand.  You only get into  
trouble when, instead of assigning 1, you are assigning (a reference  
to) some mutable object.  Then you have to think about whether you are  
copying the data or just copying a reference to it.

> Your reasoning is backwards. Call-by-value by definition implies  
> that the
> value is copied. If the value isn't copied, it can't be call-by-value.

Quite right.  We just disagree on what "value" means.  I think this is  
because Python is so restricted: everything is an object reference,  
and these are always passed by value.  So you try to gloss over the  
details which may be more obvious in languages that have other data  
types and evaluation strategies.

I'd be fine with that if it actually simplified things for Python  
newbies, but I haven't seen that it does.  Pretending that Python  
variables actually contain their objects then requires you to launch  
into long explanations of such things as why assignment doesn't make a  
copy of the data, whether objects have names, and so on.

> You shouldn't change the definition of "value" in order to hammer the
> square peg of your language into the round hole of "call-by-value"

I'm not changing the definition of "value," I'm merely being precise  
about it.  You want to be loose about it -- and keep trying to support  
that practice by citing examples where such looseness works fine --  
but when dealing with mutable types, it is NOT fine, and leads people  
into trouble.  If the "value" of x is a person named Sam of species  
Hobbit, then

   y = x
   y.species = 'Elf'

would not change Sam into an elf.  But in Python, it does.  At this  
point, you will launch into your explanation of how, not only is  
Python's calling convention different from other languages, but its  
assignment operator is quite different too, so the above doesn't do  
what you would expect it to do when dealing with object values.

But all that extra explanation becomes unnecessary if you just admit  
that x and y are mere references, and assignment statements (or  
parameter calls) copy the reference, not the object.

> especially since there has been a perfectly fine alternative name  
> for the
> behaviour since at least 1974.

Where, in the LISP community?  Why can't I find this venerated name in  
any of my CS references?

> What the Java and VB.NET communities have essentially done is redefine
> "horse" to mean "internal combustion engine" simply to avoid accepting
> that there are such things as horseless carriages.

No, they've realized that no new term is needed.  "int foo;" declares  
an integer.  "Person foo;" declares a person reference.  That there is  
no explicit syntax needed to make this a reference (unlike C++) is  
mere streamlining of the syntax, since it was realized that you ALWAYS  
want to handle objects via references.  And, once you have such  
references, you can copy them or alias them, just like any other  
type.  Nothing new here.

> *If* somebody reliably told me that assignment in "all other
> languages" (what, Forth, Lisp, Brainf*ck, Intercal, Algol-60, Ruby,  
> *all*
> of them???) meant copying, then I'd quite happily accept that Python
> assignment is different, since it clearly doesn't copy the value.

Well, I can't vouch for all of them.  But I can vouch for quite a few.

But here you go again: you're forced to claim that Python's parameter  
passing is different, AND its assignment is different, with the net  
result that the behavior is *exactly the same* as Java, .NET, and so  
on.  Doesn't that strike you as odd?  Why is it so different in so  
many ways, that just happen to cancel out and result in  
indistinguishable semantics?

> Well Joe, you've seen for yourself at least one person in this thread
> read YOUR explanation of Python's behaviour and conclude from that  
> that
> Python is call-by-reference.

Who was that?

> Then there's these:
>
> "I was under the assumption that everything in python was a reference.
> So if I code this: ... I though the contents of lst would be  
> modified."
>
> http://mail.python.org/pipermail/python-list/2006-January/360222.html

That guy's confused all right, but he'll do no better with your  
unusual definition of what "assignment" means.  Either way, we have to  
explain that "i = 4" makes i refer to something new, and does not  
affect whatever it referred to before.

> "Python passes references to objects by value (like Java), and  
> everything
> in Python is an object. This sounds simple, but then you will notice  
> that
> some data types seem to exhibit pass-by-value characteristics, while
> others seem to act like pass-by-reference... what's the deal?"
>
> http://www.goldb.org/goldblog/CommentView,guid,4eb92070-c279-44b3-
> ac2a-5d1c4f3e8115.aspx

This guy is right.  He's just pointing out that mutating an object  
tells you NOTHING about how the reference to it was passed.  That's a  
red herring that I believe you have brought up a few times too.

> And here:
>
> "Python passes all arguments using 'pass by reference'."
> http://www.penzilla.net/tutorials/python/functions/

Well this guy's just wrong, as can be easily demonstrated.  And I know  
you don't think that, but I do think he may have gotten that  
impression from listening to your explanation -- it's certainly what I  
thought you thought for a while.  (But I no longer think that, so I  
guess that's another sign of progress!)

> "Python uses bog standard call-by-reference" -- Nick Maclaren,
> University of Cambridge Computing Service:
> http://mail.python.org/pipermail/python-list/2000-April/030077.html

That guy's sure confused, isn't he?

> "I would describe Python parameter passing as call-by-value, with the
> wrinkle that the value being passed is always a reference to an  
> object."
> -- Greg Ewing, Computer Science Dept, University of Canterbury (NZ)
> http://mail.python.org/pipermail/python-list/2000-April/030315.html

And this guy's spot on (and his comments apply to every other modern  
OOP language, too, except for those like VB.NET which have an option  
to pass parameters, including references, by reference if you really  
want to).

But if nothing else, you've shown that there is a lot of confusion on  
this point, and it'd be great if we could come to some consensus and  
promote that.  I'm sure it doesn't help that we're calling it  
different things.  (And, IMHO, it also doesn't help if we call it  
something different from what the exact same behavior is called in  
other languages.)

Best,
- Joe





More information about the Python-list mailing list