I am never going to complain about Python again

F

Frank Millman

Steven D'Aprano said:
Just came across this little Javascript gem:

",,," == Array((null,'cool',false,NaN,4));

=> evaluates as true

http://wtfjs.com/2011/02/11/all-your-commas-are-belong-to-Array

I swear, I am never going to complain about Python again.

I am sure you know this, but for the record, Javascript has two equality
operators, '==' and '==='.

The double form attempts to coerce the left and right sides to the same
type, the triple form does not.

'1' == 1 returns true

'1' === 1 returns false

The moment I discovered this, I changed all my operators from the double
form to the triple form. Now I no longer have surprises of this nature.

Frank Millman
 
M

MRAB

I am sure you know this, but for the record, Javascript has two equality
operators, '==' and '==='.

The double form attempts to coerce the left and right sides to the same
type, the triple form does not.
Re "==", this page:

http://php.net/manual/en/language.operators.comparison.php

states:

"""If you compare a number with a string or the *comparison involves
numerical strings*, then each string is converted to a number and the
comparison performed numerically.""" (emphasis added)

So they get coerced to numbers if they _look_ like numbers!
 
T

Tim Chase

Re "==", this page:

http://php.net/manual/en/language.operators.comparison.php

states:

"""If you compare a number with a string or the *comparison involves
numerical strings*, then each string is converted to a number and
the comparison performed numerically.""" (emphasis added)

So they get coerced to numbers if they _look_ like numbers!

BEDEVERE: How do you know she is a number?

VILLAGER1: She looks like one!

CROWD: Right! Yeah! Yeah!

BEDEVERE: Bring her forward.

STRING: I'm not a number. I'm not a number.

BEDEVERE: Uh, but you are dressed as one.

STRING: They dressed me up like this.

Tenuously-trying-to-keep-python-related'ly yours,

-tkc
 
F

Frank Millman

MRAB said:
Re "==", this page:

http://php.net/manual/en/language.operators.comparison.php

states:

"""If you compare a number with a string or the *comparison involves
numerical strings*, then each string is converted to a number and the
comparison performed numerically.""" (emphasis added)

So they get coerced to numbers if they _look_ like numbers!

I just tested Steven's example.

",,," == Array((null,'cool',false,NaN,4)) evaluates to true

",,," === Array((null,'cool',false,NaN,4)) evaluates to false

I did look at the article that Steven linked to, but it made my eyes glaze,
so don't ask me to explain it. I am prepared to use up a few brain cells
trying to improve my own programming, but not trying to understand someone
else's 'wtf' moments! [1]

Frank

[1] Unless I have to maintain it, of course. I have been there before, and
I have some dark memories!
 
R

Roy Smith

Steven D'Aprano said:
Just came across this little Javascript gem:

",,," == Array((null,'cool',false,NaN,4));

=> evaluates as true

http://wtfjs.com/2011/02/11/all-your-commas-are-belong-to-Array

I swear, I am never going to complain about Python again.

I've just finished reading JavaScript: The Good Parts, by Douglas
Crockford (now I'm working on the harder part of re-reading it slowly,
to make sure I really understand it). Anybody who is forced to work
with javascript should read this book. It's the K&R of JS.

Anyway, one of the pieces of advice he gives is to pretend that ==
doesn't exist, and always use ===. PHP suffers from much the same
problem.

BTW, here's a Python equality oddity:
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: can't convert complex to int

If x == y, then f(x) should also equal f(y). More specifically, if x ==
y, and x is in the domain of f(), then y should also be in the domain of
f().

BTW, one of the earliest things that turned me on to Python was when I
discovered that it uses j as the imaginary unit, not i. All
right-thinking people will agree with me on this.
 
N

Neil Cerutti

I've just finished reading JavaScript: The Good Parts, by Douglas
Crockford (now I'm working on the harder part of re-reading it slowly,
to make sure I really understand it). Anybody who is forced to work
with javascript should read this book. It's the K&R of JS.

Anyway, one of the pieces of advice he gives is to pretend that ==
doesn't exist, and always use ===. PHP suffers from much the same
problem.

BTW, here's a Python equality oddity:

Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: can't convert complex to int

If x == y, then f(x) should also equal f(y). More
specifically, if x == y, and x is in the domain of f(), then y
should also be in the domain of f().

Mixed arithmetic always promotes to the wider type (except in
the case of complex numbers (Ha!)).

r == c is equivalent to r == abs(c), which returns the magintude
of the complex number.

I wonder why it was deemed reasonable to do that but not for the
float constructor to do the same, or even int.
BTW, one of the earliest things that turned me on to Python was
when I discovered that it uses j as the imaginary unit, not i.
All right-thinking people will agree with me on this.

On top of the engineering origin, j is more noticeable.
 
R

Rotwang

[...]

Mixed arithmetic always promotes to the wider type (except in
the case of complex numbers (Ha!)).

r == c is equivalent to r == abs(c), which returns the magintude
of the complex number.
What?
True
 
M

MRAB

[...]

Mixed arithmetic always promotes to the wider type (except in
the case of complex numbers (Ha!)).

r == c is equivalent to r == abs(c), which returns the magintude
of the complex number.
What?
-1 == -1 + 0j True
-1 == abs(-1 + 0j) False
1 == 0 + 1j False
1 == abs(0 + 1j)
True
Indeed.

If r is real (float) and c is complex:

r == c means r == c.real and c.imag == 0.0
 
N

Neil Cerutti

[...]

Mixed arithmetic always promotes to the wider type (except in
the case of complex numbers (Ha!)).

r == c is equivalent to r == abs(c), which returns the magintude
of the complex number.
What?

-1 == -1 + 0j True
-1 == abs(-1 + 0j) False
1 == 0 + 1j False
1 == abs(0 + 1j)
True
Indeed.

If r is real (float) and c is complex:

r == c means r == c.real and c.imag == 0.0

Woah. I thought I was going by what the docs say:

Python fully supports mixed arithmetic: when a binary
arithmetic operator has operands of different numeric types,
the operand with the “narrower” type is widened to that of the
other, where integer is narrower than floating point, which is
narrower than complex. Comparisons between numbers of mixed
type use the same rule. [2] The constructors int(), float(),
and complex() can be used to produce numbers of a specific
type.

[...]

[2] Not for complex numbers. Instead convert to floats using
abs() if appropriate.

I guess the "if appropriate" part eluded my eye. When *is* it
appropriate? Apparently not during an equal test.
False
 
I

Ian Kelly

On 10/10/2013 16:51, Neil Cerutti wrote:
[...]

Mixed arithmetic always promotes to the wider type (except in
the case of complex numbers (Ha!)).

r == c is equivalent to r == abs(c), which returns the magintude
of the complex number.

What?

-1 == -1 + 0j
True
-1 == abs(-1 + 0j)
False
1 == 0 + 1j
False
1 == abs(0 + 1j)
True
Indeed.

If r is real (float) and c is complex:

r == c means r == c.real and c.imag == 0.0

Woah. I thought I was going by what the docs say:

Python fully supports mixed arithmetic: when a binary
arithmetic operator has operands of different numeric types,
the operand with the “narrower” type is widened to that of the
other, where integer is narrower than floating point, which is
narrower than complex. Comparisons between numbers of mixed
type use the same rule. [2] The constructors int(), float(),
and complex() can be used to produce numbers of a specific
type.

[...]

[2] Not for complex numbers. Instead convert to floats using
abs() if appropriate.

I guess the "if appropriate" part eluded my eye. When *is* it
appropriate? Apparently not during an equal test.

If you click on the footnote, it takes you to:

[2]As a consequence, the list [1, 2] is considered equal to [1.0,
2.0], and similarly for tuples.

The text that you have mistakenly identified as the footnote is
actually part of the key to the "Notes" column of the numeric
operations table, where it is referred to by the "x % y" and
"divmod(x, y)" operations. Specifically, it warns of this error:
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: can't mod complex numbers.
 
N

Neil Cerutti

Woah. I thought I was going by what the docs say:

Python fully supports mixed arithmetic: when a binary
arithmetic operator has operands of different numeric types,
the operand with the ?narrower? type is widened to that of the
other, where integer is narrower than floating point, which is
narrower than complex. Comparisons between numbers of mixed
type use the same rule. [2] The constructors int(), float(),
and complex() can be used to produce numbers of a specific
type.

[...]

[2] Not for complex numbers. Instead convert to floats using
abs() if appropriate.

I guess the "if appropriate" part eluded my eye. When *is* it
appropriate? Apparently not during an equal test.

If you click on the footnote, it takes you to:

[2]As a consequence, the list [1, 2] is considered equal to [1.0,
2.0], and similarly for tuples.

The text that you have mistakenly identified as the footnote is
actually part of the key to the "Notes" column of the numeric
operations table, where it is referred to by the "x % y" and
"divmod(x, y)" operations. Specifically, it warns of this error:
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: can't mod complex numbers.

Doh!

Thanks, for that, and for the corrections. I could have avoided
all this by testing it correctly in the REPL, too.

I'll click on those footnotes instead of scanning to them from
now on.
 
O

Oscar Benjamin

I guess the "if appropriate" part eluded my eye. When *is* it
appropriate? Apparently not during an equal test.

False

If the above is genuine output then it's most likely floating point
error. I wouldn't expect any errors in that though. What version of
Python are you using and on what OS/hardware?

I get the following in Python 2.7 and 3.2 on Ubuntu 12.04 with a
32-bit AMD processor:True


Oscar
 
N

Neil Cerutti

If the above is genuine output then it's most likely floating point
error. I wouldn't expect any errors in that though. What version of
Python are you using and on what OS/hardware?

I get the following in Python 2.7 and 3.2 on Ubuntu 12.04 with a
32-bit AMD processor:
True

I get the same thing. I was apparently quite confused.
 
C

Cameron Simpson

If r is real (float) and c is complex:
r == c means r == c.real and c.imag == 0.0

Woah. I thought I was going by what the docs say:

Python fully supports mixed arithmetic: when a binary
arithmetic operator has operands of different numeric types,
the operand with the “narrower” type is widened to that of the
other, where integer is narrower than floating point, which is
narrower than complex. Comparisons between numbers of mixed
type use the same rule. [2] The constructors int(), float(),
and complex() can be used to produce numbers of a specific
type.

[...]

[2] Not for complex numbers. Instead convert to floats using
abs() if appropriate.

I guess the "if appropriate" part eluded my eye. When *is* it
appropriate? Apparently not during an equal test.

I must say that I read the footnote [2] as a directive to the
programmer. "If you need to do this, a good way is to compare
magnitudes is appropriate."

Cheers,
--
Cameron Simpson <[email protected]>

My life is a never ending battle for the forces of good.
Unfortunately, unlike many other crusaders for righteousness, in my
system of morality, the right thing to do is very often to sit around
reading the paper or watching TV. - Tim_Mefford <[email protected]>
 
D

Dennis Lee Bieber

BTW, here's a Python equality oddity:

Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: can't convert complex to int

If x == y, then f(x) should also equal f(y). More specifically, if x ==
y, and x is in the domain of f(), then y should also be in the domain of
f().

But the int(c) is a downgrade -- it would require losing all
information that the item was an element of the complex plain...

Maybe some language exists that considers "c" to be a downgradable
match to "r" (it may even be some language I've used -- but never had to
consider the condition prior). Note that in the above, the representation
of "c" doesn't even display a real component!
 
S

Steven D'Aprano

BTW, here's a Python equality oddity:

True

Mathematically, this is only to be expected.

Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: can't convert complex to int


This is also to be expected. What should int(a+bj) return?

★ int(a) + int(b)j

★ int(a)

★ int(b)

★ int(abs(a + bj))


It's quite ambiguous, there is no obvious mapping from complex to
integers, and so should raise an exception.


If x == y, then f(x) should also equal f(y).

Not necessarily. If x and y are different types, which they are here,
then function f may be defined on one type but not the other. Which is
exactly the case with int() on floats and complexes.

More specifically, if x == y,
and x is in the domain of f(), then y should also be in the domain of
f().

Incorrect. By definition, complex numbers are in the Complex domain, not
the Real domain.

Your mistake here seems to be that you're assuming that if two numbers
are equal, they must be in the same domain, but that's not the case.
(Perhaps you think that 0.0 == 0+0j should return False?) It's certainly
not the case when it comes to types in Python, and it's not even the case
in mathematics. Given:

x ∈ â„, x = 2 (reals)
y ∈ ℕ, y = 2 (natural numbers)

we have x = y, but since 1/y is undefined (there is no Natural number
1/2), 1/x != 1/y.

Now, arguably in this case we could implicitly promote y to the reals
before performing the division. I would consider that acceptable, since
there is only one way to do the promotion: natural 2 -> real 2. But going
the other way certainly isn't: demoting real x to the naturals is
ambiguous, and even if it weren't, then declaring that 1/x isn't defined
would make the whole exercise pointless.

Bringing this back to the initial example of int(0.0) == int(0+0j), to
have this work the way you want would require demoting the complex number
to the reals, and that is ambiguous. There are three distinct ways to do
this: take the real part, the imaginary part, or the absolute value. That
makes the operation "demote to real" ambiguous, the mere fact that all
three operations would happen to give the same result for this particular
number is irrelevant.
 

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,766
Messages
2,569,569
Members
45,042
Latest member
icassiem

Latest Threads

Top