Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > comp.lang.python > #74232 > unrolled thread
| Started by | Steven D'Aprano <steve@pearwood.info> |
|---|---|
| First post | 2014-07-09 07:00 +0000 |
| Last post | 2014-07-12 08:33 +0000 |
| Articles | 19 on this page of 39 — 16 participants |
Back to article view | Back to comp.lang.python
Proposal: === and !=== operators Steven D'Aprano <steve@pearwood.info> - 2014-07-09 07:00 +0000
Re: Proposal: === and !=== operators Chris Angelico <rosuav@gmail.com> - 2014-07-09 17:21 +1000
Re: Proposal: === and !=== operators Steven D'Aprano <steve@pearwood.info> - 2014-07-09 09:17 +0000
Re: Proposal: === and !=== operators Rustom Mody <rustompmody@gmail.com> - 2014-07-09 09:20 -0700
Re: Proposal: === and !=== operators Ian Kelly <ian.g.kelly@gmail.com> - 2014-07-09 11:50 -0600
Re: Proposal: === and !=== operators Cameron Simpson <cs@zip.com.au> - 2014-07-10 09:16 +1000
Re: Proposal: === and !=== operators Johannes Bauer <dfnsonfsduifb@gmx.de> - 2014-07-12 13:54 +0200
Re: Proposal: === and !=== operators Steven D'Aprano <steve+comp.lang.python@pearwood.info> - 2014-07-12 16:35 +0000
Re: Proposal: === and !=== operators Chris Angelico <rosuav@gmail.com> - 2014-07-13 02:54 +1000
Re: Proposal: === and !=== operators Roy Smith <roy@panix.com> - 2014-07-12 16:39 -0400
Re: Proposal: === and !=== operators Johannes Bauer <dfnsonfsduifb@gmx.de> - 2014-07-12 20:14 +0200
Re: Proposal: === and !=== operators Chris Angelico <rosuav@gmail.com> - 2014-07-13 09:01 +1000
Re: Proposal: === and !=== operators Roy Smith <roy@panix.com> - 2014-07-12 19:06 -0400
Re: Proposal: === and !=== operators Chris Angelico <rosuav@gmail.com> - 2014-07-13 09:15 +1000
Re: Proposal: === and !=== operators Steven D'Aprano <steve+comp.lang.python@pearwood.info> - 2014-07-13 04:48 +0000
Re: Proposal: === and !=== operators Cameron Simpson <cs@zip.com.au> - 2014-07-09 18:17 +1000
Re: Proposal: === and !=== operators Steven D'Aprano <steve@pearwood.info> - 2014-07-09 09:02 +0000
Re: Proposal: === and !=== operators Chris Angelico <rosuav@gmail.com> - 2014-07-09 19:23 +1000
Re: Proposal: === and !=== operators Devin Jeanpierre <jeanpierreda@gmail.com> - 2014-07-09 05:01 -0700
Re: Proposal: === and !=== operators Roy Smith <roy@panix.com> - 2014-07-09 08:27 -0400
Re: Proposal: === and !=== operators Steven D'Aprano <steve+comp.lang.python@pearwood.info> - 2014-07-09 12:48 +0000
Re: Proposal: === and !=== operators Tim Chase <python.list@tim.thechases.com> - 2014-07-09 13:05 -0500
Re: Proposal: === and !=== operators Steven D'Aprano <steve+comp.lang.python@pearwood.info> - 2014-07-10 01:10 +0000
Re: Proposal: === and !=== operators Ian Kelly <ian.g.kelly@gmail.com> - 2014-07-09 12:31 -0600
Re: Proposal: === and !=== operators Roy Smith <roy@panix.com> - 2014-07-09 16:47 -0400
Re: Proposal: === and !=== operators Ethan Furman <ethan@stoneleaf.us> - 2014-07-09 05:43 -0700
Re: Proposal: === and !=== operators Robert Kern <robert.kern@gmail.com> - 2014-07-09 16:27 +0100
Re: Proposal: === and !=== operators Alex Burke <alexjeffburke@gmail.com> - 2014-07-10 18:33 +0200
Re: Proposal: === and !=== operators Steven D'Aprano <steve+comp.lang.python@pearwood.info> - 2014-07-12 03:30 +0000
Re: Proposal: === and !=== operators Alan Bawden <alan@scooby-doo.csail.mit.edu> - 2014-07-12 01:07 -0400
Re: Proposal: === and !=== operators Torsten Bronger <bronger@physik.rwth-aachen.de> - 2014-07-12 08:05 +0200
Re: Proposal: === and !=== operators Torsten Bronger <bronger@physik.rwth-aachen.de> - 2014-07-12 08:14 +0200
Re: Proposal: === and !=== operators Chris Angelico <rosuav@gmail.com> - 2014-07-12 16:06 +1000
Re: Proposal: === and !=== operators Ethan Furman <ethan@stoneleaf.us> - 2014-07-11 23:11 -0700
Re: Proposal: === and !=== operators Chris Angelico <rosuav@gmail.com> - 2014-07-12 16:39 +1000
Re: Proposal: === and !=== operators Marko Rauhamaa <marko@pacujo.net> - 2014-07-12 10:06 +0300
Re: Proposal: === and !=== operators Ethan Furman <ethan@stoneleaf.us> - 2014-07-11 23:53 -0700
Re: Proposal: === and !=== operators Chris Angelico <rosuav@gmail.com> - 2014-07-12 17:25 +1000
Re: Proposal: === and !=== operators Steven D'Aprano <steve+comp.lang.python@pearwood.info> - 2014-07-12 08:33 +0000
Page 2 of 2 — ← Prev page 1 [2]
| From | Steven D'Aprano <steve+comp.lang.python@pearwood.info> |
|---|---|
| Date | 2014-07-09 12:48 +0000 |
| Message-ID | <53bd3a1d$0$29995$c3e8da3$5496439d@news.astraweb.com> |
| In reply to | #74249 |
On Wed, 09 Jul 2014 08:27:28 -0400, Roy Smith wrote: > We would have *three* ways to compare for equality (==, ===, and is). `is` does not, never has, and never will, be a test for equality. py> x = [] py> y = [] py> x is y False -- Steven
[toc] | [prev] | [next] | [standalone]
| From | Tim Chase <python.list@tim.thechases.com> |
|---|---|
| Date | 2014-07-09 13:05 -0500 |
| Message-ID | <mailman.11703.1404929192.18130.python-list@python.org> |
| In reply to | #74250 |
On 2014-07-09 12:48, Steven D'Aprano wrote:
> On Wed, 09 Jul 2014 08:27:28 -0400, Roy Smith wrote:
>
> > We would have *three* ways to compare for equality (==, ===, and
> > is).
>
> `is` does not, never has, and never will, be a test for equality.
>
> py> x = []
> py> y = []
> py> x is y
> False
I too am in the -1 category for adding an extra operator-suite
because of the confusion it will add (this is one of my biggest
pet peeves with PHP/JS).
If you want to compare things in a NaN-aware way, you can either
spell it out explicitly:
if x == y or (math.isnan(x) and math.isnan(y)):
do_stuff()
or create a wrapper function to do that for you:
def equalish(x, y):
return x == y or (math.isnan(x) and math.isnan(y))
if equalish(w, z):
print("yep")
else:
print("nope")
-tkc
[toc] | [prev] | [next] | [standalone]
| From | Steven D'Aprano <steve+comp.lang.python@pearwood.info> |
|---|---|
| Date | 2014-07-10 01:10 +0000 |
| Message-ID | <53bde7ff$0$29995$c3e8da3$5496439d@news.astraweb.com> |
| In reply to | #74269 |
On Wed, 09 Jul 2014 13:05:22 -0500, Tim Chase wrote: > If you want to compare things in a NaN-aware way, you can either spell > it out explicitly: > > if x == y or (math.isnan(x) and math.isnan(y)): > do_stuff() But do we really want any arbitrary NAN to compare equal-ish with every other NAN? There are 9007199254740990 distinct NANs (slightly less than 0.05% of the total number of floats). Much to my disappointment, frexp doesn't return the payload and exponent of NANs, at least not on Linux: py> math.frexp(NAN) (nan, 0) so it can't be used to distinguish different NANs. -- Steven
[toc] | [prev] | [next] | [standalone]
| From | Ian Kelly <ian.g.kelly@gmail.com> |
|---|---|
| Date | 2014-07-09 12:31 -0600 |
| Message-ID | <mailman.11705.1404930731.18130.python-list@python.org> |
| In reply to | #74250 |
On Wed, Jul 9, 2014 at 12:05 PM, Tim Chase
<python.list@tim.thechases.com> wrote:
> def equalish(x, y):
> return x == y or (math.isnan(x) and math.isnan(y))
With more generality:
def nan_type(x):
if isinstance(x, numbers.Complex):
if cmath.isnan(x): return 'qnan'
elif isinstance(x, decimal.Decimal):
if x.is_qnan(): return 'qnan'
if x.is_snan(): return 'snan'
return None
def equalish(x, y):
if x is y or x == y: return True
x_nan = nan_type(x)
return x_nan is not None and x_nan == nan_type(y)
Have I missed any cases?
[toc] | [prev] | [next] | [standalone]
| From | Roy Smith <roy@panix.com> |
|---|---|
| Date | 2014-07-09 16:47 -0400 |
| Message-ID | <roy-9B49B8.16472209072014@news.panix.com> |
| In reply to | #74250 |
In article <53bd3a1d$0$29995$c3e8da3$5496439d@news.astraweb.com>, Steven D'Aprano <steve+comp.lang.python@pearwood.info> wrote: > On Wed, 09 Jul 2014 08:27:28 -0400, Roy Smith wrote: > > > We would have *three* ways to compare for equality (==, ===, and is). > > `is` does not, never has, and never will, be a test for equality. > > py> x = [] > py> y = [] > py> x is y > False That is a very narrow legalistic way of looking at things. If you don't like the word "equality", substitute a more generic word, such as "sameness" We continually have threads about when to use "==" and when to use "is". Clearly, there is confusion about them. Adding another way to test for sameness will just increase the confusion.
[toc] | [prev] | [next] | [standalone]
| From | Ethan Furman <ethan@stoneleaf.us> |
|---|---|
| Date | 2014-07-09 05:43 -0700 |
| Message-ID | <mailman.11688.1404912787.18130.python-list@python.org> |
| In reply to | #74232 |
On 07/09/2014 12:00 AM, Steven D'Aprano wrote: > > I propose: [adding new operators] -1 Too much added confusion, too little gain. -- ~Ethan~
[toc] | [prev] | [next] | [standalone]
| From | Robert Kern <robert.kern@gmail.com> |
|---|---|
| Date | 2014-07-09 16:27 +0100 |
| Message-ID | <mailman.11694.1404919684.18130.python-list@python.org> |
| In reply to | #74232 |
On 2014-07-09 08:00, Steven D'Aprano wrote: > At the moment, Python has two (in)equality operators, == and != which > call __eq__ and __ne__ methods. Some problems with those: > > > * Many people expect == to always be reflexive (that is, x == x for > every x) but classes which customise __eq__ may not be. > > * The == operator requires __eq__ to return True or False > (or NotImplemented) and raises TypeError if it doesn't, which > makes it impossible to use == with (say) three-valued or fuzzy > logic. No, it doesn't. It can return anything. [~] |1> x = np.arange(5) [~] |2> x == 3 array([False, False, False, True, False], dtype=bool) You can blame Numeric/numpy for that feature getting in. :-) Now certainly, many uses of __eq__, like containment comparisons, do assume that the result is a bool(able). -- Robert Kern "I have come to believe that the whole world is an enigma, a harmless enigma that is made terrible by our own mad attempt to interpret it as though it had an underlying truth." -- Umberto Eco
[toc] | [prev] | [next] | [standalone]
| From | Alex Burke <alexjeffburke@gmail.com> |
|---|---|
| Date | 2014-07-10 18:33 +0200 |
| Message-ID | <mailman.11730.1405010015.18130.python-list@python.org> |
| In reply to | #74232 |
On 9 July 2014 09:00, Steven D'Aprano <steve@pearwood.info> wrote:
> At the moment, Python has two (in)equality operators, == and != which
> call __eq__ and __ne__ methods. Some problems with those:
>
>
> * Many people expect == to always be reflexive (that is, x == x for
> every x) but classes which customise __eq__ may not be.
>
> * The == operator requires __eq__ to return True or False
> (or NotImplemented) and raises TypeError if it doesn't, which
> makes it impossible to use == with (say) three-valued or fuzzy
> logic.
>
>
> I propose:
>
> * The == operator be redefined to *always* assume reflexivity, that
> is, it first compares the two arguments using `is` before calling
> the __eq__ methods.
>
> * That's a backwards-incompatible change, so you need to enable it
> using "from __future__ import equals" in Python 3.5, and then to
> become the default behaviour in 3.6.
(course I forgot to reply-all first first time I sent this)
Hi,
Aside from really reaching for Python for all my own projects (mostly
due to enjoying the language and it's design) the day job is mostly writing
server side code for Javascript on node.js. With that perspective I really
think those extra operators will cause confusion - granted the distinction
between == and === is for different reasons there but it's just complexity
to need to explain why there are different modes of comparison. With ==
and is I think when to use which is much more clear cut.
That being said though the point you raised that:
different objects can implement __eq__ such that it may or may not be
reflexive in different cases
could do with an answer. It's the implicitness and differing behaviour that
get me, and it seems to be one of the roots of the disagreement. When
should NaN compare equal, when not etc.
So, (this is likely a terrible idea) what if == was made always always reflexive
and a from __future__ to have any NaN being compared raise a new
NonReflexiveComparison exception? Advantages:
* no equality special cases to explain
* make potentially meaningless comparisons immediately clear
* if you really want to compare NaNs you can catch the case and
return math.isnan(left) and math.isnan(right)
The obvious issue is possibility of exceptions from arbitrary == comparisons.
PS hoping these comments comments might prove useful :-)
Thanks, Alex J Burke.
[toc] | [prev] | [next] | [standalone]
| From | Steven D'Aprano <steve+comp.lang.python@pearwood.info> |
|---|---|
| Date | 2014-07-12 03:30 +0000 |
| Message-ID | <53c0abe8$0$9505$c3e8da3$5496439d@news.astraweb.com> |
| In reply to | #74232 |
Thanks to everyone who has commented. Some responses:
* I was completely mistaken about == enforcing the rule
that __eq__ returns True or False. I have no idea where
I got that idea from, sorry for the noise.
* I disagree that having two equals operators, == and ===,
would be confusing. The Javascript/PHP model doesn't apply:
- In Javascript and PHP, the shorter, more attractive
version == does the wrong thing and is harmful, hence
everyone needs to learn about === immediately.
- In my proposal, the shorter, more attractive version
== does what everyone already assumes == will do. It's
only specialists who need to learn about === .
* But having said that, I find myself trying to solve a problem
reported by Anders which I do not understand, cannot replicate,
and although I'm willing to give him the good faith benefit of
the doubt, I find myself less and less convinced that the
problem is what he thinks it is.
To be specific, the one concrete piece of code Anders has posted is a
completely generic "detect changes" function which he claims is broken by
the presence of NANs. That may be, but his code is not runnable (it uses
undefined methods that could do anything) so cannot be tested, and I
cannot replicate his problem.
NANs or no NANs, a generic "detect changes" function already fails to
work in some circumstances:
py> data = [1, 2.0, 3.0, 4.0]
py> old = data[:]
py> old == data # No changes made yet, should return True
True
py> data[0] = 1.0 # Change of type.
py> old == data # Should return False
True
But perhaps we only care about changes in value, not type. NAN or no NAN,
list equality works fine:
py> data = [1.0, 2.0, float('nan'), 4.0]
py> old = data[:]
py> old == data # No changes made yet, should return True
True
py> data[3] = 104.0
py> old == data # Should return False
False
The only time it may fail, for some definition of "fail", is when the NAN
is replaced by another NAN of the same payload but different identity.
But I still fail to understand Ander's use-case here, how a NAN might be
replaced by another NAN, or why he wants to compare two different NANs as
equal.
Since I do not understand Ander's problem, I cannot hope to solve it. So
I withdraw my suggestion. Thanks to everyone who listened.
--
Steven
[toc] | [prev] | [next] | [standalone]
| From | Alan Bawden <alan@scooby-doo.csail.mit.edu> |
|---|---|
| Date | 2014-07-12 01:07 -0400 |
| Message-ID | <w2dbnsvcghb.fsf@scooby-doo.csail.mit.edu> |
| In reply to | #74365 |
Steven D'Aprano <steve+comp.lang.python@pearwood.info> writes:
> But perhaps we only care about changes in value, not type. NAN or no NAN,
> list equality works fine:
>
> py> data = [1.0, 2.0, float('nan'), 4.0]
> py> old = data[:]
> py> old == data # No changes made yet, should return True
> True
You lost me right here. If list equality is determined by comparing
lists element-by-element, and the second element of old is _not_ equal
to the second element of data, then why should old and data be equal?
In fact, I find myself puzzled about exactly how list equality is
actually defined. Consider:
>>> a = float('nan')
>>> x = [1, a, 9]
>>> y = [1, a, 9.0]
>>> x == y
True
So is there some equality predicate where corresponding elements of x
and y are equal?
>>> map(operator.eq, x, y)
[True, False, True]
It's not "==".
>>> map(operator.is_, x, y)
[True, True, False]
And it's not "is".
--
Alan Bawden
[toc] | [prev] | [next] | [standalone]
| From | Torsten Bronger <bronger@physik.rwth-aachen.de> |
|---|---|
| Date | 2014-07-12 08:05 +0200 |
| Message-ID | <874mynjen4.fsf@physik.rwth-aachen.de> |
| In reply to | #74366 |
Hallöchen!
Alan Bawden writes:
> [...]
>
> You lost me right here. If list equality is determined by
> comparing lists element-by-element, and the second element of old
> is _not_ equal to the second element of data, then why should old
> and data be equal?
I think Python first tests for identity, and falls back to equality
(or the other way round). This behaviour is questionable in my
opinion.
Tschö,
Torsten.
--
Torsten Bronger Jabber ID: torsten.bronger@jabber.rwth-aachen.de
or http://bronger-jmp.appspot.com
[toc] | [prev] | [next] | [standalone]
| From | Torsten Bronger <bronger@physik.rwth-aachen.de> |
|---|---|
| Date | 2014-07-12 08:14 +0200 |
| Message-ID | <87zjgfhznj.fsf@physik.rwth-aachen.de> |
| In reply to | #74369 |
Hallöchen!
Torsten Bronger writes:
> Alan Bawden writes:
>
>> [...]
>>
>> You lost me right here. If list equality is determined by
>> comparing lists element-by-element, and the second element of old
>> is _not_ equal to the second element of data, then why should old
>> and data be equal?
>
> I think Python first tests for identity, and falls back to
> equality (or the other way round). This behaviour is questionable
> in my opinion.
See also
https://mail.python.org/pipermail/python-bugs-list/2006-August/035010.html
Tschö,
Torsten.
--
Torsten Bronger Jabber ID: torsten.bronger@jabber.rwth-aachen.de
or http://bronger-jmp.appspot.com
[toc] | [prev] | [next] | [standalone]
| From | Chris Angelico <rosuav@gmail.com> |
|---|---|
| Date | 2014-07-12 16:06 +1000 |
| Message-ID | <mailman.11769.1405145213.18130.python-list@python.org> |
| In reply to | #74366 |
On Sat, Jul 12, 2014 at 3:07 PM, Alan Bawden
<alan@scooby-doo.csail.mit.edu> wrote:
> Steven D'Aprano <steve+comp.lang.python@pearwood.info> writes:
>
>> But perhaps we only care about changes in value, not type. NAN or no NAN,
>> list equality works fine:
>>
>> py> data = [1.0, 2.0, float('nan'), 4.0]
>> py> old = data[:]
>> py> old == data # No changes made yet, should return True
>> True
>
> You lost me right here. If list equality is determined by comparing
> lists element-by-element, and the second element of old is _not_ equal
> to the second element of data, then why should old and data be equal?
>
> In fact, I find myself puzzled about exactly how list equality is
> actually defined.
In the Python 3 docs, it's made a bit clearer, at least as regards the
'in' and 'not in' operators: it's an identity check followed by an
equality check - "x is y or x == y". The same comparison is done for
equality, although it's not strictly described there (at least, I
couldn't find it). There are a lot of these sorts of corner cases that
aren't made really clear in the docs, because the verbosity would be
more of a problem than the omission - I consider them to be like "The
land continues to burn" on Obsidian Fireheart [1] or the reminder text
on Madness [2]; if you go to the Magic: The Gathering Comprehensive
Rulebook, you can find the exact "code-accurate" details on how either
one works, but that takes several pages of verbiage, and it's much
better to just say "you may cast it for its madness cost instead of
putting it into your graveyard".
For the most part, the identity check is a pure optimization. Most
Python objects compare equal to themselves. It only VERY occasionally
matters (like when there's a NaN in your list), and for those cases,
you have the interactive interpreter to try things at.
ChrisA
[1] http://gatherer.wizards.com/Pages/Card/Details.aspx?multiverseid=192224
[2] eg http://gatherer.wizards.com/Pages/Card/Details.aspx?multiverseid=118892
[toc] | [prev] | [next] | [standalone]
| From | Ethan Furman <ethan@stoneleaf.us> |
|---|---|
| Date | 2014-07-11 23:11 -0700 |
| Message-ID | <mailman.11771.1405146988.18130.python-list@python.org> |
| In reply to | #74366 |
On 07/11/2014 10:07 PM, Alan Bawden wrote:
> Steven D'Aprano <steve+comp.lang.python@pearwood.info> writes:
>
>> But perhaps we only care about changes in value, not type. NAN or no NAN,
>> list equality works fine:
>>
>> py> data = [1.0, 2.0, float('nan'), 4.0]
>> py> old = data[:]
>> py> old == data # No changes made yet, should return True
>> True
>
> You lost me right here. If list equality is determined by comparing
> lists element-by-element, and the second element of old is _not_ equal
> to the second element of data, then why should old and data be equal?
>
> In fact, I find myself puzzled about exactly how list equality is
> actually defined. Consider:
>
> >>> a = float('nan')
> >>> x = [1, a, 9]
> >>> y = [1, a, 9.0]
> >>> x == y
> True
>
> So is there some equality predicate where corresponding elements of x
> and y are equal?
>
> >>> map(operator.eq, x, y)
> [True, False, True]
>
> It's not "==".
>
> >>> map(operator.is_, x, y)
> [True, True, False]
>
> And it's not "is".
class list:
def __eq__(self, other):
if len(self) != len(other):
return False
for this, that in zip(self, other):
if this is that or this == that:
continue
break
else:
return True
return False
--
~Ethan~
[toc] | [prev] | [next] | [standalone]
| From | Chris Angelico <rosuav@gmail.com> |
|---|---|
| Date | 2014-07-12 16:39 +1000 |
| Message-ID | <mailman.11772.1405147177.18130.python-list@python.org> |
| In reply to | #74366 |
On Sat, Jul 12, 2014 at 4:11 PM, Ethan Furman <ethan@stoneleaf.us> wrote: > class list: > def __eq__(self, other): > if len(self) != len(other): > return False > for this, that in zip(self, other): > if this is that or this == that: > continue > break > else: > return True > return False Seems a little elaborate. Why not just return straight from the loop, instead of breaking and using else? :) ChrisA
[toc] | [prev] | [next] | [standalone]
| From | Marko Rauhamaa <marko@pacujo.net> |
|---|---|
| Date | 2014-07-12 10:06 +0300 |
| Message-ID | <87mwcf6opo.fsf@elektro.pacujo.net> |
| In reply to | #74374 |
Chris Angelico <rosuav@gmail.com>: > On Sat, Jul 12, 2014 at 4:11 PM, Ethan Furman <ethan@stoneleaf.us> wrote: >> class list: >> def __eq__(self, other): >> if len(self) != len(other): >> return False >> for this, that in zip(self, other): >> if this is that or this == that: >> continue >> break >> else: >> return True >> return False > > Seems a little elaborate. Why not just return straight from the loop, > instead of breaking and using else? :) But look at that keyword density! That single function demonstrates 80% of Python syntax making it a great educational tool. Marko
[toc] | [prev] | [next] | [standalone]
| From | Ethan Furman <ethan@stoneleaf.us> |
|---|---|
| Date | 2014-07-11 23:53 -0700 |
| Message-ID | <mailman.11773.1405149423.18130.python-list@python.org> |
| In reply to | #74366 |
On 07/11/2014 11:39 PM, Chris Angelico wrote: > On Sat, Jul 12, 2014 at 4:11 PM, Ethan Furman <ethan@stoneleaf.us> wrote: >> class list: >> def __eq__(self, other): >> if len(self) != len(other): >> return False >> for this, that in zip(self, other): >> if this is that or this == that: >> continue >> break >> else: >> return True >> return False > > Seems a little elaborate. Why not just return straight from the loop, > instead of breaking and using else? :) Because I'm tired, and it seemed like a good excuse to show else with for, and because I'm tired. :) -- ~Ethan~
[toc] | [prev] | [next] | [standalone]
| From | Chris Angelico <rosuav@gmail.com> |
|---|---|
| Date | 2014-07-12 17:25 +1000 |
| Message-ID | <mailman.11774.1405149942.18130.python-list@python.org> |
| In reply to | #74366 |
On Sat, Jul 12, 2014 at 4:53 PM, Ethan Furman <ethan@stoneleaf.us> wrote: > Because I'm tired, and it seemed like a good excuse to show else with for, > and because I'm tired. :) Excellent justification. I withdraw the criticism. :) ChrisA
[toc] | [prev] | [next] | [standalone]
| From | Steven D'Aprano <steve+comp.lang.python@pearwood.info> |
|---|---|
| Date | 2014-07-12 08:33 +0000 |
| Message-ID | <53c0f2be$0$9505$c3e8da3$5496439d@news.astraweb.com> |
| In reply to | #74366 |
On Sat, 12 Jul 2014 01:07:28 -0400, Alan Bawden wrote:
> Steven D'Aprano <steve+comp.lang.python@pearwood.info> writes:
>
>> But perhaps we only care about changes in value, not type. NAN or no
>> NAN, list equality works fine:
>>
>> py> data = [1.0, 2.0, float('nan'), 4.0]
>> py> old = data[:]
>> py> old == data # No changes made yet, should return True True
>
> You lost me right here. If list equality is determined by comparing
> lists element-by-element, and the second element of old is _not_ equal
> to the second element of data, then why should old and data be equal?
Because practicality beats purity.
Outside of the specialist areas of IEEE-754 floating point NANs, and SQL
NUL, it is a basic property of *nearly everything* that x equals itself,
for any x. This property is called "reflexivity", and is considered by
some (although not me) to be absolutely fundamental, never to be violated
under any circumstances.
(To be clear, I'm talking about reflexivity of *equality* specifically,
not of every operator. We wouldn't expect x > x, for example -- the
"greater than" operator is not reflexive.)
While IEEE-754, and SQL, have good reasons for violating the reflexivity
of equals, that upsets a lot of people. Given:
data = [1.0, 2.0, 3.0]
data == data
it would be surprising, and annoying, more often than useful if the
equality test returned False. Replace any of the floats with a NAN, and
the same surprise and annoyance applies.
In the case of Python, lists and other builtin containers partially
violate the specialist rules of IEEE-754 NAN handling, by using "is"
identity test as a shortcut for equality. Effectively, they assume that
equality is always reflexive. This was introduced as an optimization,
since == can be quite expensive in Python, whereas "is" requires only a
fast pointer comparison and is very cheap.
I support this optimization, even if it violates the non-reflexivity of
NANs. NANs are specialised values, and outside of the narrow confines of
IEEE-754 arithmetic, their non-reflexivity is more of a nuisance than
anything else.
(Some would argue that *even within* IEEE-754 arithmetic, non-reflexivity
is a nuisance. For now, I prefer to remain neutral in that argument.)
> In fact, I find myself puzzled about exactly how list equality is
> actually defined.
You'd have to check the C source code, but I would expect something like
this (only written in C):
class list:
def __eq__(self, other):
if self is other:
return True
elif isinstance(other, list):
if len(self) != len(other):
return False
for a, b in zip(self, other):
if not (a is b or a == b):
return False
return True
else:
return NotImplemented # Let other decide.
--
Steven
[toc] | [prev] | [standalone]
Page 2 of 2 — ← Prev page 1 [2]
Back to top | Article view | comp.lang.python
csiph-web