Explanation of list reference

C

Chris Angelico

You just need to recognise that
objects can contain themselves:

py> L = []
py> L.append(L)
py> L in L
True


Of course, if you are a fan of the Doctor Who television show, you won't
be concerned by this. If the TARDIS can materialise inside itself, then
there isn't any problem with lists containing themselves either.

They certainly can. In my MUD, every object has a location (which may
be the equivalent of None); generally, a person's location is a room,
and a grabbable object's location is either a room or a person, but
it's possible for a room to have a location... a Dungeon Master can
create a workroom, which is in his inventory, and then enter that
workroom.

Incidentally, the destruction of an object simply involves moving it
to nowhere. Since "nowhere" doesn't keep any references to the things
put there, those objects promptly cease to exist. It's just like
Western society - you don't actually destroy anything, you just throw
it away (out of sight, out of mind), and let the garbage collector
dispose of it for you :)

ChrisA
 
C

Chris Angelico

On Sat, 15 Feb 2014 15:37:20 +1100, Chris Angelico wrote:

[...]
This is why dice exist in a variety of colors [1]. Indistinguishable yet
distinct dice...

Since they have different colours, they can be distinguished and aren't
indistinguishable.

Sorry, what I meant was that different colors are available for
purchase, as a means of avoiding this problem. If you buy a dozen dice
in mixed colors, you can simply declare "the red one is the hundreds,
the blue one is tens, the green one is units", which is the most
common solution to this exact issue of dice being indistinguishable
yet distinct.
One might also distinguish three dice by position in space ("the die
closest to the wall counts as the HUNDREDS digit, the one closest to me
counts as the TENS digit, and the one closest to you counts as the UNITS
digit")

Yes, but prior to rolling, you can't necessarily know what's going to
be easy to determine. Rolling dice tends to randomize their positions
somewhat, and it's impractical to get out the tape measure to
determine which one is closest to the wall :)
or by space ("roll this die first for the HUNDREDS, then roll
that one for TENS, then this third one for UNITS").

Distinguishing by time is the other common method that I mentioned. In
that case, there's really no reason to distinguish them at all, so you
can use the same object three times - like using the string "foobar"
three times and perhaps finding that it's the same object.
Or scent, or texture, or the typeface used for the numbers.

Then they're not indistinguishable :)

Having grown up in a business that sells dice (though, oddly enough,
not for RPGs - I learned that d12s are popular for practicing
multiplication tables, not that they're used for a barbarian's hit
points and great-axe damage), I know how many identical dice you can
get hold of. We had trays and trays of them at one point... then
migrated to bulk bags. Though we usually tried to split them up, 50
dice per bag, so we could keep some track of inventory. And we were
retailing, and dice weren't a huge part of our business. There are
plenty of ways for dice to differ, but that's like having 5, 5.0, 5L
(if Py2), and (5+0j), all of which are five, but all of which are
distinct and must be kept separate.

ChrisA
 
I

Ian Kelly

Whats the notion of object identity is the question.
Ok so you reject the memory addr as an 'implementation detail'
Then you are obliged to provide some other way of understanding object-identity

I thought that I did. Repeating myself from what you quoted above:

If two objects share the same creation, then they're the same object.
 
M

Marko Rauhamaa

Ned Batchelder said:
On 2/14/14 4:43 PM, Marko Rauhamaa wrote:
Yes, sometimes for teaching reasons, you have to over-simplify or even
introduce artificial constructs. I'd recommend acknowledging them as
such.

When you say, "There are two fundamentally different kinds of values
in Python," or "So we have four kinds of (memory) slots," you aren't
letting on that this is a teaching construct. It sounds like you mean
that this is how Python actually works.

I'd use words like, "This is an oversimplification, but might
help...", or "You can think of it like ...".

Strictly speaking, I'm not simplifying, but giving an equivalent,
alternative description. I admit that the word "fundamentally" was a bad
choice. I'm not even sure my description was a good illustration. I
definitely was not referring to CPython and was trying to keep the
discussion separate from the implementation of the day.

BTW, I also wasn't oversimplifying, but complicating by bringing in an
unnecessary dichotomy. The challenge is how to present Python's value
model in the most digestible way. For example, how is a beginnger to
understand what's going on in:

n += 1

Is it easier to think that the number held by the variable n is
incremented by 1, or is it easier to understand it orthodoxly through
instantiations and references?


Marko
 
M

Marko Rauhamaa

Chris Angelico said:
Can you give an example of an ambiguous case?

The "x is y" test may yield different outcomes in different, valid
Python implementations:

4 is 4
(x,) is (x,)
"hello" is "hello"


Marko
 
M

Marko Rauhamaa

Ben Finney said:
You should never need to predict the result of an ‘is’ operation.
(More precisely, for *some* cases you can predict it, but for other
cases you can't.)

No problem there. You have to understand "is" well to use it.

Referring to "objects in memory" when defininig "is" leads to circular
definitions. It think the best way to define the semantics of "is" is
through constraints:

1. if x is y then y ix x

2. if x is y and y is z then x is z

3. after x = y, x is y

4. if x is y, then x == y

That's why "is" is not introductory material.

The constraints define a relation that coincides with == wherever it is
defined. So why would you ever use "is" instead of "=="? After all, all
well-defined programs would behave identically after replacing "is" with
"==". Really, the only reason would be performance; "is" is often faster
to evaluate than "==".


Marko
 
M

Marko Rauhamaa

Christian Gollwitzer said:
Still they are connected. I can imagin that id() is just a debugging
tool for extensions. What useful applications does it have outside of
this?

Calculating hash keys quickly.


Marko
 
M

Marko Rauhamaa

Marko Rauhamaa said:
1. if x is y then y ix x
2. if x is y and y is z then x is z
3. after x = y, x is y
4. if x is y, then x == y

A new attempt:

0. x is x
1. if x is y then y ix x
2. if x is y and y is z then x is z
3. after x = y, x is y
4. if x is y and x == x, then x == y
5. id(x) == id(y) iff x is y

Does that cover it?


Marko
 
S

Steven D'Aprano

The "x is y" test may yield different outcomes in different, valid
Python implementations:

4 is 4
(x,) is (x,)
"hello" is "hello"


But none of those examples are ambiguous. They're merely unspecified by
the language definition. Any specific implementation of Python will
return either True or False; it may be predictable, or it might be
impossible to predict until runtime, but either way we know that every
non-broken Python virtual machine must either treat the two operands as
the same object or different objects.

These are ambiguous sentences:

I saw the man with the binoculars.
Police help assault victim.
Once there was a blind carpenter who picked up his hammer and saw.
Look at that cat with one eye.

"A Python implementation can choose whether or not to re-use immutable
objects" is not ambiguous. It's just a choice.
 
S

Steven D'Aprano

It think the best way to define the semantics of "is" is
through constraints:

1. if x is y then y ix x

2. if x is y and y is z then x is z

3. after x = y, x is y

4. if x is y, then x == y

Incorrect.

py> x = float('nan')
py> y = x
py> x is y
True
py> x == y
False

That's why "is" is not introductory material.

No. "is" is not introductory material because it is an attractive
nuisance for beginners. Beginners have a tendency to think that "is" is a
synonym for "equals", as it can be in English. Sometimes it appears to
work:

x = 2
y = x*3 - 4
x is y
=> probably returns True

but in other cases it fails, confusing the beginner.

With the exception of "is None", beginners almost never need "is".

The constraints define a relation that coincides with == wherever it is
defined.

It certainly does not.

class Wacky:
def __eq__(self, other):
return random.random() < 0.5

So why would you ever use "is" instead of "=="? After all, all
well-defined programs would behave identically after replacing "is" with
"==". Really, the only reason would be performance; "is" is often
faster to evaluate than "==".

Incorrect. "is" is NOT equivalent to ==, the two are not guaranteed to do
the same thing, you CANNOT safely replace "is" with == or visa versa, and
the meaning of the "is" operator is completely different from the meaning
of the == operator.

The "is" operator tests whether the two operands are the same object,
nothing more, nothing less. The == operator tests whether the two
operands compare equal.
 
S

Steven D'Aprano

Am 15.02.14 01:57, schrieb Chris Angelico:
Can you give an example of an ambiguous case? Fundamentally, the 'is'
operator tells you whether its two operands are exactly the same
object, nothing more and nothing less, so I assume your "ambiguous
cases" are ones where it's possible for two things to be either the
same object or two indistinguishable ones.

What about the thing I posted down in this thread?
import numpy as np
a=np.array([1, 2, 3, 4])
b=a[:]
id(a) 140267900969344
id(b)
140267901045920

So, a and b are different things, right?

Correct. They are different objects. But they may share underlying state.

b[1]=37
b array([ 1, 37, 3, 4])
a
array([ 1, 37, 3, 4])

And indeed numpy arrays do share state. Why? No idea. Somebody thought
that it was a good idea. (Not me though...)

Still they are connected. I can imagin that id() is just a debugging
tool for extensions. What useful applications does it have outside of
this?

Very few.
 
S

Steven D'Aprano

A new attempt:

0. x is x
1. if x is y then y ix x
2. if x is y and y is z then x is z
3. after x = y, x is y
4. if x is y and x == x, then x == y
5. id(x) == id(y) iff x is y

Python implementations are free to re-use IDs after the object is
destroyed. CPython does; Jython and IronPython do not. So #5 needs to
point out that the condition id(x) == id(y) only applies if x and y still
exist.

# Counter-example
py> x = 230000
py> idx = id(x)
py> del x
py> y = 420000
py> idy = id(y)
py> idx == idy
True


(This is *implementation dependent* so your mileage my vary.)

Does that cover it?

No. Your definition describes some properties of identity-equivalence,
but doesn't explain what identity actually means.
 
G

Gregory Ewing

Steven said:
(1) General relativity tells us that not all observers will agree on the
space-time coordinates of two objects, since not all observers agree on a
single frame of reference.

But that doesn't mean they won't agree about whether
objects are identical or not! The coordinates they
use to describe spacetime locations may differ, but
they will agree on whether or not they are equal.
A Lorentz transformation can't cause a single point
in spacetime to split into two, or two distinct points
to merge into one.
(2) Quantum mechanics tells us that objects are not located at a single
space-time coordinate. Objects are "smeared out" over space (and time).
We cannot really talk about the location of an object, but only about the
probability of a measurement registering the object at a certain location.

But that doesn't mean you can stuff two objects into
the same space at the same time. What we perceive as
solid objects are composed of fermions, which obey
the Pauli exclusion principle. That means you can't
have more than one of them in a given quantum state.
While you *could* have two of them equally spread out
over all of space, they would then have to be
separated in some other dimension such as momentum
or spin.

So if you replace "space-time coordinates" with
"quantum state", the original statement remains
essentially true.
 
C

Chris Angelico

A new attempt:

Sorry, hadn't seen this when I posted.
0. x is x

This is the definition of identity.
1. if x is y then y ix x

Yes, because if x is y, there is absolutely no difference between
using one of those names or the other, in any context.
2. if x is y and y is z then x is z

Extension of the above. The first statement proves that you can
substitute 'x' for 'y' in the second without changing its truthiness;
therefore, based on the definition of identity, 'x is z' must be
identical to 'y is z'.
3. after x = y, x is y

This is the definition of assignment. (Obviously this axiom depends on
x and y being simple names and nothing tampering with the situation in
any way. But yes, this is exactly what assignment is.)
4. if x is y and x == x, then x == y

Yes. As in case 2, 'x is y' implies that you can substitute 'x' for
'y' or vice versa. Therefore, if x == x, then y == y, and x == y, and
y == x; because in each case, what you're doing is "object #1423443,
are you equal to object #1423443 or not?", regardless of the name you
use to access that object.
5. id(x) == id(y) iff x is y

This is the definition of id(). Note that it does depend on something
holding a reference to each of x and y; if it's possible for the
objects' lifetimes to not overlap, it's possible for them to reuse
ids:
[1,2,3] is [2,3,4] False
id([1,2,3]) == id([2,3,4])
True

But if x and y are simple names (and therefore retaining their
referent objects), then your statement is valid.
Does that cover it?

Largely axiomatically, yes.

ChrisA
 
G

Gregory Ewing

Steven said:
IDs are a proxy for distinct objects. If you live in a country with an ID
card of some sort, then the IDs acts as an identifier for each unique
individual. But countries without ID cards don't lack unique individual
people.

"You are Number Six."
"I am not an id()! I am an individual object!"
 
G

Gregory Ewing

Jussi said:
Would it help to say that in case 1 the relevant statement acts on the
variable while in case 2 it acts on the value of the variable?

I would try to avoid using words like "value" and "variable",
because they don't have well-defined meanings in Python.

The way I would put it is that

a = b

changes which object the name 'a' refers to, whereas

a = b

does not.
 
M

Marko Rauhamaa

Steven D'Aprano said:
# Counter-example
py> x = 230000
py> idx = id(x)
py> del x
py> y = 420000
py> idy = id(y)
py> idx == idy
True

I don't accept that as a counterexample. You will have to produce:

(id(x) == id(y)) == (x is y)
(This is *implementation dependent* so your mileage my vary.)


No. Your definition describes some properties of identity-equivalence,
but doesn't explain what identity actually means.

That's the point. I don't think id() and "is" have any abstract meaning
on top of the formal axioms.


Marko
 
G

Gregory Ewing

Chris said:
But yes, this is an expression, and it evaluates to a reference.

Well, *all* expressions in Python evaluate to references,
so that's not really saying much.
 
C

Chris Angelico

Well, *all* expressions in Python evaluate to references,
so that's not really saying much.

Because everything in Python is an object, and objects always are
handled by their references. This wouldn't be true in every language
(eg it's not true of Java's unboxed types), but it's intrinsic to
Python's object model.

ChrisA
 

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
473,774
Messages
2,569,596
Members
45,143
Latest member
DewittMill
Top