Are python types used during operator overloading?

I have the following code:

a = str('5') b = int(5) a == b # False 

But if I subclass int and override __cmp__ :

 class A(int): def __cmp__(self, other): return super(A, self).__cmp__(other) a = str('5') b = A(5) a == b # TypeError: A.__cmp__(x,y) requires y to be a 'A', not a 'str' 

Why are these two different? Is the python runtime capturing a TypeError thrown by int.__cmp__() and interpreting this as False ? Can someone tell me a bit in cpython 2.x source which shows how this works?

+6
source share
3 answers

The documentation is not completely explicit on this, but see here :

If both are numbers, they are converted to a common type. Otherwise, objects of different types are always compared unevenly and ordered sequentially, but arbitrarily. You can control the behavior of comparing objects of non-built-in types by defining the __cmp__ method or rich comparison methods, such as __gt__ , described in the section Special Method Names.

This (in particular, the implicit contrast between "objects of different types" and "objects of non-built-in types") indicates that the normal process of actually calling comparison methods is skipped for built-in types: if you try to compare objects of two built-in types of dfferent (and not numeric ), they just close to automatic False.

+5
source

The comparison decision tree for a == b looks something like this:

  • python calls a.__cmp__(b)
    • a checks that b is a suitable type
    • If b is the appropriate type, return -1 , 0 or +1
    • If b not, return NotImplented
  • if -1 , 0 or +1 returned, python is executed; otherwise
  • If NotImplented is returned, try
  • b.__cmp__(a)
    • b checks that a is a suitable type
    • if a is a suitable type, return -1 , 0 or +1
    • If a not, return NotImplemented
  • if -1 , 0 or +1 returned, python is executed; otherwise
  • If NotImplented returns again, the answer is False

Inaccurate answer, but hopefully this helps.

+3
source

If I understand your problem correctly, you need something like:

 >>> class A(int): ... def __cmp__(self, other): ... return super(A, self).__cmp__(A(other)) # <--- A(other) instead of other ... >>> a = str('5') >>> b = A(5) >>> a == b True 

Update

As for the 2.x cpython source, you can find the reason for this result in typeobject.c in the wrap_cmpfunc function, which actually checks two things: this comparison function is func and other is a subtype for self .

 if (Py_TYPE(other)->tp_compare != func && !PyType_IsSubtype(Py_TYPE(other), Py_TYPE(self))) { // .... } 
-2
source

Source: https://habr.com/ru/post/925601/


All Articles