Friday, April 29, 2005

how well do you know python, part 6

class foo(list):
    def __eq__(self, other):
        raise 'foo.__eq__ called'

>>> help(list.__eq__)
Help on wrapper_descriptor:

__eq__(...)
    x.__eq__(y) <==> x==y

>>> [].__eq__(foo())
True
>>> [] == foo()
Traceback (most recent call last):
  File "", line 1, in ?
  File "", line 3, in __eq__
foo.__eq__ called

Help says those two statements should be equivalent. Why aren't they?

11 comments:

Bader said...
This comment has been removed by a blog administrator.
Bader said...

I think it's because when you do:
a == b
(where b is an object that contains the __eq__ method)
it means b.__eq__(a)

Jonathan Ellis said...

try

foo() == []

paul cannon said...

I think I know the answer, but I don't know if I should give it away so soon and ruin it for everyone else :) Someone on an earlier question gave a rot13 answer, so I'll do that too. Am I right?

Jura gur glcr bs gur bowrpg ba gur evtug-unaq fvqr bs n pbzcnevfba vf n fhoglcr bs gur glcr bs gur bowrpg ba gur yrsg-unaq fvqr, vgf evpu-pbzcnevfba shapgvbaf ner hfrq vafgrnq bs gubfr sebz gur yrsg-unaq fvqr, jura ninvynoyr, naq ersyrpgrq (< orpbzrf >, rgp, ohg == fgnlf gur fnzr). Nf sne nf V xabj, vg'f whfg n fcrpvny pnfr, ohg vg qbrf fbeg bs znxr
frafr jura lbh guvax nobhg ubj lbh'q hfhnyyl hfr fhoglcrf va guvf jnl.

Gur bgure bcrengvba, jurer lbh'ir gnxra gur __rd__ nggevohgr bs [] qverpgyl anghenyyl unf n qvssrerag erfhyg, fvapr gur zrgubq pubfra vf abg hc gb gur evpu-pbzcnevfba znpuvarel.

mark said...

Although they are meant to be commutative (is that the right one?) they have to be defined so they are. The __eq__ of the left hand object gets called:

class hat( object ):
    def __eq__(self , other ):
     print "I am hat"
     print "other is a %s" % ( other.__class__.__name__ )
     return True

class tree( object ):
    def __eq__(self , other ):
     print "I am tree"
     print "other is a %s" % ( other.__class__.__name__ )
     return False

a = hat()
b = tree()

a == b
b == a

mark said...

forgot to show the outcome of that code :-)

it prints:

I am hat
other is a tree
I am tree
other is a hat

mark said...

I am not paying enough attention - that is the answer to something else... oops!

mark said...

The real answer:

class hat( object ):
    def __eq__(self , other ):
     return NotImplemented

class tree( object ):
    def __eq__(self , other ):
     print "I am tree"
     print "other is a %s" % ( other.__class__.__name__ )
     return True

a = hat()
b = tree()

a == b
b == a

returns:
I am tree
other is a hat
I am tree
other is a hat

The NotImplemented forces it to try the other available __eq__()

paul cannon said...

mark: yeah, but list.__eq__() doesn't return NotImplemented! :)

Jonathan Ellis said...

Paul: you are correct. (Source for those curious about this and related esoterica: uggc://qbpf.clguba.bet/ers/pbrepvba-ehyrf.ugzy)

Anonymous said...

Also at http://docs.python.org/ref/coercion-rules.html

...
Sorry. Had to.