[Tutor] True and 1 [was Re: use of the newer dict types]
Albert-Jan Roskam
fomcl at yahoo.com
Thu Aug 1 21:28:35 CEST 2013
----- Original Message -----
> From: eryksun <eryksun at gmail.com>
> To: Albert-Jan Roskam <fomcl at yahoo.com>
> Cc: "tutor at python.org" <tutor at python.org>
> Sent: Wednesday, July 31, 2013 4:16 PM
> Subject: Re: [Tutor] True and 1 [was Re: use of the newer dict types]
>
> On Mon, Jul 29, 2013 at 7:33 AM, Albert-Jan Roskam <fomcl at yahoo.com>
> wrote:
>> Wow, too bad __cmp__ is no longer present. Not so much for cmp(), but
>> because it's such a compact way to define all the comparison methods.
>> Btw, my book says "Python will supply the __ne__() (not equal)
>> inequality operator automatically if wel implement __eq__ but don't
>> implement __ne__()". [Programming in Python 3 (2009), M. Summerfield,
>> p.213]
>
> That's true in 3.x. The base object type has a default rich comparison
> that uses __eq__ to implement __ne__ (but not vice versa).
>
> The CPython tp_richcompare slot function is object_richcompare in
> Objects/typeobject.c. Here's a link to 3.3.2:
>
> http://hg.python.org/cpython/file/d047928ae3f6/Objects/typeobject.c#l3175
>
> In 2.x the base object type doesn't implement rich comparisons. You'll
> get the default comparison in CPython (by id or type name), which
> won't necessarily be consistent with __eq__.
>
> Here's something to riddle out. Why does CPython 2.x make 22 method
> calls for the following cmp()?
>
> class A(object):
> def _print(self, op):
> print '%s.__%s__' % (type(self).__name__, op)
> def __eq__(self, other):
> self._print('eq')
> return NotImplemented
> def __lt__(self, other):
> self._print('lt')
> return NotImplemented
> def __gt__(self, other):
> self._print('gt')
> return NotImplemented
> def __coerce__(self, other):
> self._print('coerce')
> return NotImplemented
>
> class B(A):
> pass
>
> >>> cmp(A(), B())
> B.__eq__
> A.__eq__
> A.__eq__
> B.__eq__
> B.__eq__
> A.__eq__
> B.__gt__
> A.__lt__
> A.__lt__
> B.__gt__
> B.__gt__
> A.__lt__
> B.__lt__
> A.__gt__
> A.__gt__
> B.__lt__
> B.__lt__
> A.__gt__
> A.__coerce__
> B.__coerce__
> B.__coerce__
> A.__coerce__
> -1
Six comparisons for each operator (6 x 3) and the 4 calls to __coerce__ seems much.
So you arrvie at 8 calls by 3 operator methods called "bidirectionally" (A-B and B-A) + two calls to __coerce__?
> Why is the order BAABBA repeated 3 times? As a hint, I'll group it
> like this: BA--AB--BA.
>
> Jython does this 'right' (IMHO) with 8 calls. PyPy appears to be
> playing tight to what's technically allowed and steps over the line.
> It only uses 4 calls, but it doesn't attempt a __coerce__, which I
> think is technically wrong.
I did "help(coerce)" and it seems straightforward, however, I can't connect it to your remark about coercion.
I thought pypy would behave differently with e.g cmp(1, "x"), compared to cpython
antonia at antonia-HP-2133 ~ $ pypy
Python 2.7.2 (1.9+dfsg-1, Jun 19 2012, 23:23:45)
[PyPy 1.9.0 with GCC 4.7.0] on linux2
Type "help", "copyright", "credits" or "license" for more information.
And now for something completely different: ``'that's definitely a case of
"uh????"'''
>>>> cmp(1, "x")
-1
>>>> cmp(1, 1.0)
0
>>>> cmp(-1, 1.0)
-1
>>>> quit()
antonia at antonia-HP-2133 ~ $ python
Python 2.7.3 (default, Apr 10 2013, 05:09:49)
[GCC 4.7.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> cmp(1, "x")
-1
>>> cmp(1, 1.0)
0
>>> cmp(-1, 1.0)
-1
# I was hoping this, I mean dis, would shed some light on this
>>> import dis
>>> dis.dis("cmp(0, 0)")
0 DUP_TOPX 28781
3 STORE_SLICE+0
4 <48>
5 <44>
6 SLICE+2
7 <48>
8 STORE_SLICE+1
>>> dis.dis("cmp(0, 0.0)")
0 DUP_TOPX 28781
3 STORE_SLICE+0
4 <48>
5 <44>
6 SLICE+2
7 <48>
8 <46>
9 <48>
10 STORE_SLICE+1
More information about the Tutor
mailing list