From: John Posner on
Alf said (2/13/2010 8:34 PM):

> Names in Python refer to objects.
>
> Those references can be copied via assignment.
>
> That's (almost) all.
>
> And it provides a very short and neat way to describe pass by sharing.

Alf also said (2/13/2010 8:43 PM):

> * Steve Howell:
> > This thread is interesting on many levels. What is the core
> > question that is being examined here?
>
> I think that regarding the technical it is whether a Python name
> refers to an object or not. I maintain that it does, and that the
> reference can be copied, and that the semantics of the language
> requires this and is defined in terms of this. Steve Holden,
> D'Aprano and many others maintain that there are no references, or
> that if there are then they're only an implementation aspect, i.e.
> that conceiveable one could have an implementation without them.

Steve D'Aprano said (2/14/2010 12:13 AM):

> That's not to say that the general concept of references (as in "to
> refer to") isn't valuable when discussing Python. If you want to say
> that (e.g.) following
>
> x = 1
>
> the name "x" refers to (or even points to!) the object 1, my
> objections will be mild or non-existent. In that sense, it's probably
> impossible to program without some sort of "references": the computer
> manipulates variables or objects directly, while we manipulate
> characters in source code. The only way to write a program is to use
> some abstract thing (a name, an offset, whatever) that refers, in
> some fashion, to a collection of bits in the computer's memory. But
> to go from that to the idea that (say) x is a pointer does so much
> violence to the concept of pointer and has so much room for confusion
> that it is actively harmful.

I think most of the technical argument in this thread comes down to the
various forms of the word *refer*. After execution of this Python statement:

x = 5

.... we can use this English-language statement:

the name *x* refers to the value *5*

(If anyone has more than Steve's "mild" objection, please speak up!)

The English-language statement uses the VERB "refers". It is not the
same as using the NOUN "reference":

*x* is a reference to the value *5*

Why not? Because using the NOUN form suggests that you're talking about
a particular kind of object in the world Python, as in these statements:

*x* is a string
*x* is a function
*x* is a class

But Python does not define *reference* objects -- by which I mean that
executing *import types; dir(types)* produces a long list of object-type
names, and there's nothing like a "reference" on that list.

(I suspect there's a better way to make this "there are no reference
objects" argument. Can anyone help?)

Amending the statement to:

the name *x* is a reference to the value *5*

.... doesn't really help matters. Is *x* a NAME or is it a REFERENCE?

Looking again at Alf's assertion:

> [the core technical question is] whether a Python name
> refers to an object or not. I maintain that it does, and that the
> reference can be copied,

.... and Alf's example (message dated 2/10/2010 5:02 PM):

> For example,
>
> x = s[0]
>
> accesses the object that s points (refers) to.

I believe Alf would characterize this assignment statement as a
situation in which "a reference is copied" [using the NOUN form of
"refer"]. But no object is copied during execution of this statement.
Moreover, saying "a reference is copied" might mislead a Python newbie
into thinking that some kind of "reference object" exists that can be
copied by Python statements. So it's better to describe the situation
using the VERB form of "refer":

assigns the name *x* to the object that *s[0]* refers to


-John
From: Arnaud Delobelle on
John Posner <jjposner(a)optimum.net> writes:
[...]
>> x = s[0]
[...]
> assigns the name *x* to the object that *s[0]* refers to

s[0] does not refer to an object, it *is* an object (once evaluated of
course, otherwise it's just a Python expression).

--
Arnaud
From: Steven D'Aprano on
On Mon, 15 Feb 2010 21:25:23 +0000, Arnaud Delobelle wrote:

> John Posner <jjposner(a)optimum.net> writes: [...]
>>> x = s[0]
> [...]
>> assigns the name *x* to the object that *s[0]* refers to
>
> s[0] does not refer to an object, it *is* an object (once evaluated of
> course, otherwise it's just a Python expression).

Precisely. Treated as an expression, that is, as a string being evaluated
by the compiler, we would say that it *refers to* an object (unless
evaluation fails, in which case it refers to nothing at all). But treated
as whatever you get after the compiler is done with it, that is, post-
evaluation, we would say that it *is* an object.

This subtle distinction is essentially the difference between a label and
the thing that is labeled.



--
Steven
From: Alf P. Steinbach on
* Steven D'Aprano:
> On Mon, 15 Feb 2010 21:25:23 +0000, Arnaud Delobelle wrote:
>
>> John Posner <jjposner(a)optimum.net> writes: [...]
>>>> x = s[0]
>> [...]
>>> assigns the name *x* to the object that *s[0]* refers to
>> s[0] does not refer to an object, it *is* an object (once evaluated of
>> course, otherwise it's just a Python expression).
>
> Precisely. Treated as an expression, that is, as a string being evaluated
> by the compiler, we would say that it *refers to* an object (unless
> evaluation fails, in which case it refers to nothing at all). But treated
> as whatever you get after the compiler is done with it, that is, post-
> evaluation, we would say that it *is* an object.
>
> This subtle distinction is essentially the difference between a label and
> the thing that is labeled.

The main differences between a pure functional language where that view can hold
and be reasonable, and a language like Python, are that

* Python assignments change which object a name refers to, /at runtime/.

- Name binding is run time action, not a compile time action.
Without run time binding names couldn't be reassigned. s = 1; s = 2

* Some Python objects are modifiable (a.k.a. mutable).

- This is particularly important when two or more names refer to the
same object and that object is modified.

That is, a simple-minded transfer of concepts from pure functional programming
to Python breaks down in these cases[1].

I hope this explanation of exactly where the functional programming enthusiasts
here go wrong can be of help to readers of the thread, although I've given up
hope on those holding the functional programming view (since I'm only human, and
even the Gods contend in vain against that sort of thing).


Cheers & hth.,

- Alf

Notes:
[1] Steven D'Aprano's focus on compilation rather than execution mainly ignores
the first point, that a name in given a statement in a loop, say, can refer to
different objects in different loop iterations. Happily the Python language
specification explains binding as a run-time action. Binding is not a compile
time action in Python, it is a run-time action, and can bind a given name in a
given statement within the same routine execution, to different objects, and the
language specification of course uses the phrase "refers to" to explain the
situation after a run time binding.
From: John Posner on
On 2/15/2010 6:09 PM, Steven D'Aprano wrote:
> On Mon, 15 Feb 2010 21:25:23 +0000, Arnaud Delobelle wrote:
>
>> John Posner<jjposner(a)optimum.net> writes: [...]
>>>> x = s[0]
>> [...]
>>> assigns the name *x* to the object that *s[0]* refers to
>>
>> s[0] does not refer to an object, it *is* an object (once evaluated of
>> course, otherwise it's just a Python expression).
>
> Precisely. Treated as an expression, that is, as a string being evaluated
> by the compiler, we would say that it *refers to* an object (unless
> evaluation fails, in which case it refers to nothing at all). But treated
> as whatever you get after the compiler is done with it, that is, post-
> evaluation, we would say that it *is* an object.
>
> This subtle distinction is essentially the difference between a label and
> the thing that is labeled.

Is this your only quibble with my writeup? If, so, I'm gratified. And
your objections make perfect sense. Still, I'll attempt to justify my
phrasing. I was originally going to write:

assigns the name *x* to the object that THE NAME *s[0]* refers to

.... but I didn't want to start a distracting argument on the use of the
phrase *the name* to describe the 4-char string *s[0]*. So now I'll try
to (briefly) make my case.

Yes, it might be more correct to say that *s[0]* is an expression
(equivalent to the more obvious expression *s.__getitem__(0)*). But in
common usage, the 4-char string *s[0]* _behaves_ like a name. If you
accept this viewpoint, the story on Python assignment statements becomes
quite simple ...

Syntactic sugar aside, there are only two kinds of assignment statements:

1. NAME = EXPRESSION

The EXPRESSION creates a new object, and the NAME is assigned to that
object. Examples:

x = x + 1
obj = MyClass(1, 2, "red")
mywordlist = mysentence.split()

2. NAME2 = NAME1

No new object is created. NAME2 becomes another name (an "alias") for
the existing object that currently has NAME1 assigned to it. Examples:

y = x
s[0] = s[42]
mydict["spamwich"] == this_sandwich
obj.color = MYCOLORS.LTGREEN

This viewpoint might fail in advanced areas of Python programming:
properties/descriptors, double-underscore methods, etc. But in my own
day-to-day usage (admittedly, I'm a hobbyist Python programmer, not a
professional), it's never failed me to think this way:

* A dict is a collection of user-devised names, each of which
is assigned to an object.
* A list/tuple is an interpreter-maintained collection of integer
names (0, 1, 2, ...), each of which is assigned to an object.
* A class instance is very much like a dict.

Tx,
John