why () is () and [] is [] work in other way?

R

Rotwang

I have spent some time searching for a bug in my code, it was due to
different work of "is" with () and []:
() is () True
[] is []
False

(Python 2.7.2+ (default, Oct 4 2011, 20:03:08)
[GCC 4.6.1] )

Is this what it should be or maybe yielding unified result is better?
D.

The reason that "[] is []" evaluates to false is because lists are
mutable and each expression "[]" evaluates to a different object.
Therefore you can change one without changing the other:
a, b = [], []
a.append(None)
a [None]
b
[]

On the other hand tuples are immutable, so there's no danger in having
each literal () evaluate to the same object - since you can't change a
tuple but only replace a reference to a tuple with a reference to
another tuple, there's no need to have the two "()"s in something like

evaluate to different objects, since there is no danger that one can
affect the value of b by doing stuff to a.

I believe it says somewhere in the Python docs that it's undefined and
implementation-dependent whether two identical expressions have the same
identity when the result of each is immutable, though I can't find the
quotation right now. If my recollection is correct then you probably
shouldn't rely on something like "() is ()" giving the same answer
across platforms.
 
A

Alain Ketterlin

dmitrey said:
I have spent some time searching for a bug in my code, it was due to
different work of "is" with () and []:
() is () True
[] is []
False

(Python 2.7.2+ (default, Oct 4 2011, 20:03:08)
[GCC 4.6.1] )

Is this what it should be or maybe yielding unified result is better?

Tuples are immutable, while lists are not. Because tuples are immutable,
there is no point in having several empty tuples: one value is enough,
and "is" recognizes this. Lists are different, they can change "value"
(contents), and several names can be bound to the same list (in other
words, you can have side-effects on a list). With:

a = []
b = a
a.append(42)
print b

you get [42]. If instead you do:

a = []
b = []
a.append(42)
print b

you get the expected []. I.e., you need several distinct empty lists,
to make sure they can change value independently.

(In case you wonder: lists in Python are not linked lists of cons-cells,
they are more monolithic structures, and two lists cannot share a common
tail.)

-- Alain.
 
J

john.tantalo

I believe it says somewhere in the Python docs that it's undefined and
implementation-dependent whether two identical expressions have the same
identity when the result of each is immutable

I was curious where that might be on my system, and found the disagreement with the ((),) case and up.

(Python 2.7.1, Darwin 11.3.0, GCC 4.2.1)
 
A

Alexander Blinne

Am 21.04.2012 05:25, schrieb Rotwang:
Alain Ketterlin said:
Tuples are immutable, while lists are not.

If you really want to have fun, consider this classic paradox:
[] is [] False
id([]) == id([])
True

Huh. This is not what I would have expected. What gives?

This happens only because the first [] gets destroyed after evaluation
of id([]). The second [] then by accident gets the same id as the first
one had.
False

Greetings
 
R

Rotwang

Am 21.04.2012 05:25, schrieb Rotwang:
Tuples are immutable, while lists are not.

If you really want to have fun, consider this classic paradox:

[] is []
False
id([]) == id([])
True

Huh. This is not what I would have expected. What gives?

This happens only because the first [] gets destroyed after evaluation
of id([]). The second [] then by accident gets the same id as the first
one had.

Thanks.
 
G

gst

Le samedi 21 avril 2012 10:46:39 UTC+2, Alexander Blinne a écrit :
Am 21.04.2012 05:25, schrieb Rotwang:

This happens only because the first [] gets destroyed after evaluation
of id([]). The second [] then by accident gets the same id as the first
one had.
a = []
b = []
id(a) == id(b)
False

Greetings

Hi,

I played (python3.2) a bit on that and :

case 1) Ok to me (right hand side is a tuple, whose elements are evaluated one per one and have same effect as your explanation (first [] is destroyedright before the second one is created) :
x, y = id([]), id([])
x == y True


case 2) also ok to me:
x = id([]) ; y = id([])
x == y True


case 3) NOT ok to me :
x = id([])
y = id([])
x == y False


case 4) ok to me :
x = id([])
y = id([])
return x == y


I'd have thought that cases 2&3 are totally, while 3&4 nearly, syntactically equal and that case 3 is the incorrect result..

how would you explain case 3 vs cases 2 and 4 ??


regards,

gs.
 
B

Bernd Nawothnig

I have spent some time searching for a bug in my code, it was due to
different work of "is" with () and []:True

You should better not rely on that result. I would consider it to be
an implementation detail. I may be wrong, but would an implementation
that results in

() is () ==> False

be correct or is the result True really demanded by the language
specification?

Same for that.
(Python 2.7.2+ (default, Oct 4 2011, 20:03:08)
[GCC 4.6.1] )

Is this what it should be or maybe yielding unified result is better?

See above.




Bernd
 
S

Steven D'Aprano

I have spent some time searching for a bug in my code, it was due to
different work of "is" with () and []:
True

You should better not rely on that result. I would consider it to be an
implementation detail. I may be wrong, but would an implementation that
results in

() is () ==> False

be correct or is the result True really demanded by the language
specification?

It would be correct, and the result True absolutely is NOT demanded by
the language. For example, Jython does not make that same optimization:

steve@runes:~$ jython
Jython 2.5.1+ (Release_2_5_1, Aug 4 2010, 07:18:19)
[OpenJDK Client VM (Sun Microsystems Inc.)] on java1.6.0_18
Type "help", "copyright", "credits" or "license" for more information.False


so code which relies on it is already broken.


Python the language makes no promises that literals will always evaluate
to the same object. The ONLY such promises that it makes are that a small
handful of special constants are singletons:

None
NotImplemented
True
False

and perhaps one or two others. Everything else is an accident of the
implementation.

The CPython interpreter is especially aggressive in optimizing multiple
literals in the same line. Compare this:
True

with this:
False


Again, this is an accident of implementation, and cannot be relied on.
 
J

John Nagle

Bad design. Where "is" is ill-defined, it should raise ValueError.

A worse example, one which is very implementation-dependent:

http://stackoverflow.com/questions/306313/python-is-operator-behaves-unexpectedly-with-integers
False

Operator "is" should be be an error between immutables
unless one is a built-in constant. ("True" and "False"
should be made hard constants, like "None". You can't assign
to None, but you can assign to True, usually with
unwanted results. It's not clear why True and False
weren't locked down when None was.)

John Nagle
 
J

John Roth

Bad design. Where "is" is ill-defined, it should raise ValueError.

A worse example, one which is very implementation-dependent:

http://stackoverflow.com/questions/306313/python-is-operator-behaves-unexpectedly-with-integers

False

Operator "is" should be be an error between immutables
unless one is a built-in constant. ("True" and "False"
should be made hard constants, like "None". You can't assign
to None, but you can assign to True, usually with
unwanted results. It's not clear why True and False
weren't locked down when None was.)

John Nagle

Three points. First, since there's no obvious way of telling whether an arbitrary user-created object is immutable, trying to make "is" fail in that case would be a major change to the language. Given the next point, I expectthat a request to change Python to do it would be rejected immediately.

Second: the definition of "is" states that it determines whether two objects are the same object; this has nothing to do with mutability or immutability. It's an implementation detail whether an immutable object is implemented as a singleton. Some common cases (None, True, False and the empty tuple)are specified to be that in the language definition, but it's not specified for the general case.

The id([]) == id([]) thing is a place where cPython's implementation isshowing through. It won't work that way in any implementation that uses garbage collection and object compaction. I think Jython does it that way, I'm not sure about either IronPython or PyPy.

Third: True and False are reserved names and cannot be assigned to in the 3..x series. They weren't locked down in the 2.x series when they were introduced because of backward compatibility.

John Roth
 
J

John Nagle

Three points. First, since there's no obvious way of telling whether
an arbitrary user-created object is immutable, trying to make "is"
fail in that case would be a major change to the language.

If a program fails because such a comparison becomes invalid, it
was broken anyway.

The idea was borrowed from LISP, which has both "eq" (pointer
equality) and and "equals" (compared equality). It made somewhat
more sense in the early days of LISP, when the underlying
representation of everything was well defined.
Second: the definition of "is" states that it determines whether two
objects are the same object; this has nothing to do with mutability
or immutability.

The id([]) == id([]) thing is a place where cPython's implementation
is showing through. It won't work that way in any implementation that
uses garbage collection and object compaction. I think Jython does it
that way, I'm not sure about either IronPython or PyPy.

That represents a flaw in the language design - the unexpected
exposure of an implementation dependency.
Third: True and False are reserved names and cannot be assigned to in
the 3.x series. They weren't locked down in the 2.x series when they
were introduced because of backward compatibility.

That's one of the standard language designer fuckups. Somebody
starts out thinking that 0 and 1 don't have to be distinguished from
False and True. When they discover that they do, the backwards
compatibility sucks. C still suffers from this.

John Nagle
 
S

Steven D'Aprano

Bad design. Where "is" is ill-defined, it should raise ValueError.

"is" is never ill-defined. "is" always, without exception, returns True
if the two operands are the same object, and False if they are not. This
is literally the simplest operator in Python.

John, you've been using Python for long enough that you should know this.
I can only guess that you are trolling, although I can't imagine why.

A worse example, one which is very implementation-dependent:

http://stackoverflow.com/questions/306313/python-is-operator-behaves- unexpectedly-with-integers
True # this is an expected result

Why do you expect that? What part of the language semantics makes you
think that the two statements:

a = 256
b = 256

must use the one object instead of creating two distinct objects?

False

Operator "is" should be be an error between immutables unless one is a
built-in constant.

I cannot imagine any rationale for that insane design choice.

For starters, it makes it impossible to use custom sentinels when you
need to distinguish between None as a valid argument and "argument
missing". E.g.:

_SENTINEL = object()

def func(x, y=_SENTINEL):
if y is _SENTINEL:
y = something_else()
process(x, y)

("True" and "False" should be made hard constants,
like "None". You can't assign to None, but you can assign to True,
usually with unwanted results.

True and False were made keywords over three years ago, in Python 3.0.

http://docs.python.org/dev/whatsnew/3.0.html#changed-syntax

It's not clear why True and False weren't locked down when None was.)

It's pretty clear to me.

Assignment to None has never been a common thing to do, hence the amount
of code broken by making None a keyword in Python 2.4 was insignificant.

On the other hand, assignment to True and False was *very* common for
code written prior to version 2.3, hence making True and False keywords
before version 3 would have broken a lot of otherwise working code for
little or no benefit.
 
A

Alexander Blinne

Am 21.04.2012 14:51, schrieb gst:
Hi,

I played (python3.2) a bit on that and :

case 1) Ok to me (right hand side is a tuple, whose elements are evaluated one per one and have same effect as your explanation (first [] is destroyed right before the second one is created) :
x, y = id([]), id([])
x == y True


case 2) also ok to me:
x = id([]) ; y = id([])
x == y True


case 3) NOT ok to me :
x = id([])
y = id([])
x == y False


case 4) ok to me :
x = id([])
y = id([])
return x == y


I'd have thought that cases 2&3 are totally, while 3&4 nearly, syntactically equal and that case 3 is the incorrect result..

how would you explain case 3 vs cases 2 and 4 ??

It is simply not defined if, after creation and destruction of an empty
list with some id, a newly created empty list should carry the same id
or not. In cases 1,2 and 4 it happens, but in case 3 it doesn't. This is
simply an implementation detail and neither behaviour is right or wrong.

Alex
 
J

John Nagle

"is" is never ill-defined. "is" always, without exception, returns True
if the two operands are the same object, and False if they are not. This
is literally the simplest operator in Python.

John, you've been using Python for long enough that you should know this.
I can only guess that you are trolling, although I can't imagine why.

Because the language definition should not be what CPython does.
As PyPy advances, we need to move beyond that.

John Nagle
 
P

Paul Rubin

Kiuhnm said:
I can't think of a single case where 'is' is ill-defined.

If I can't predict the output of

print (20+30 is 30+20) # check whether addition is commutative
print (20*30 is 30*20) # check whether multiplication is commutative

by just reading the language definition and the code, I'd have to say
"is" is ill-defined.
You're blaming 'is' for revealing what's really going on. 'is' is
/not/ implementation-dependent. It's /what's going on/ that's
implementation-dependent.
"a is b" is true iff 'a' and 'b' are the same object. Why should 'is'
lie to the user?

Whether a and b are the same object is implementation-dependent.
 
S

Steven D'Aprano

If I can't predict the output of

print (20+30 is 30+20) # check whether addition is commutative
print (20*30 is 30*20) # check whether multiplication is
commutative

by just reading the language definition and the code, I'd have to say
"is" is ill-defined.

The failure to predict the result of the above has nothing to do with
"is". Your test doesn't test what you think it does, because the output
doesn't just depend on the behaviour of "is". Aside from the properties
of arithmetic, the result printed depends on at least six factors:

* the behaviour of "is" (known)
* the behaviour of the Python interpreter when evaluating arithmetic
expressions (undefined)
* the behaviour of the interpreter when creating objects (undefined)
* the presence or absence of a keyhole optimizer (undefined)
* and how aggressive it is (undefined)
* any other optimizations the compiler might apply (undefined)

The *one* factor which actually is well-defined by the language and
completely predictable is the thing that you are John are blaming for
your failure to predict the outcome! That's simply surreal.

It isn't the "is" operator that is ill-defined. What actually is ill-
defined is the circumstances where a Python implementation uses the same
object for equal results. And that is as it should be. The decision to
recreate or reuse objects when needed should not be part of the language
definition. Why do you care whether a, b = 1+2, 5-2 creates two objects
or one? At most, that's a quality of implementation issue. It certainly
doesn't affect the semantics of the language.

Whether a and b are the same object is implementation-dependent.

And that has absolutely nothing to do with the behaviour of "is". The
"is" operator is not responsible for whether a and b are the same object.

The "is" operator has an exact definition. There is nothing ill-defined
about the "is" operator. That definition is simple enough for me to quote
it in full:

The operators is and is not test for object identity: x is y is
true if and only if x and y are the same object. x is not y
yields the inverse truth value.

Taken from the last paragraph of here:
http://docs.python.org/py3k/reference/expressions.html#is


Short of having "is" be a null-op that always returns False, there are no
changes you can make to the definition of "is" that will make "a is b"
any more predictable.
 
B

Bernd Nawothnig

If I can't predict the output of

print (20+30 is 30+20) # check whether addition is commutative
print (20*30 is 30*20) # check whether multiplication is commutative

by just reading the language definition and the code, I'd have to say
"is" is ill-defined.

"is" was never designed for comparing literals or expressions.

the expression

20+30 is 30+20

maybe syntactically correct but is nevertheless pretty senseless and
you can, of course, not check commutativity with it.

For checking commutativity you have to use:

20+30 == 30+20
Whether a and b are the same object is implementation-dependent.
True

Should be guaranteed and implementation-independent.




Bernd
 

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,777
Messages
2,569,604
Members
45,224
Latest member
BettieToom

Latest Threads

Top