← index #6175PR #3391
Related · high · value 0.317
QUERY · ISSUE

Lookup of operator builtins can fail with multiple inheritance

openby nickovsopened 2020-06-19updated 2020-06-21
py-core

When looking up a method that implements an operator (such as __int__() or __lshift__()) on an object who's class uses multiple inheritance, and an earlier base classes is a native type that does not implement that operator, then an implementation of the required method will not be found in a later base class that does implement it.

Take for instance the following example:

class Foo:
    def __int__(self):
        return 123

class Bar(Foo, list):
    pass

class Baz(list, Foo):
   pass

print(int(Bar([])))
print(int(Baz([])))

On C Python this prints the expected:

123
123

On Micropython the second call raises a TypeError:

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

This is because mp_obj_class_lookup() checks to see if a native type has the necessary unary_op or binary_op function pointer but does not check to see if the specific operator code is implemented. If a native type is found that has the required operator function pointer the search for an implementation stops there, even if it doesn't implement the desired operator code, preventing a later, usable implementation from being found.

CANDIDATE · PULL REQUEST

RFC/WIP py/objtype: user classes: Allow to lookup __new__() method.

closedby pfalconopened 2017-10-28updated 2021-05-18

new() method is present by definition in each class, because each class
inherits from "object". But due to effects of multiple inheritance and
subclassing native types, looking it up is tricky: object.new should
be the last choice, if a more specific version is found (in one of multiple
bases, or in native type), that should be used.

This patch implements this behavior by wrapping existing attribute lookup
function, and looking inside "object" only if the otiginal function doesn't
find anything. This relies on "object" not being present explicitly in the
base class chain (otherwise multiple inheritance case will be broken -
object.new will be found while following the very first inheritance
branch, while other branches may have more specific new).

This also leads to additional stack usage on each lookup due to extra
function call.

Keyboard

j / / n
next pair
k / / p
previous pair
1 / / h
show query pane
2 / / l
show candidate pane
c
copy suggested comment
r
toggle reasoning
g i
go to index
?
show this help
esc
close overlays

press ? or esc to close

copied