Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Why is __truediv__ not getting called?

I have made a class called Emulate. It takes an object and takes the attributes of the object.

class Emulate:
    def __init__(self, obj):
        for attr in dir(obj):
            if attr != '__class__':
                setattr(self, attr, getattr(obj, attr))

Now, I want to emulate the integer 1:

one = Emulate(1)

However, I can’t use / when trying to divide:

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

print(one / 2)

gives TypeError: unsupported operand type(s) for /: 'Emulate' and 'int'.

But, if I explicitly call __truediv__:

print(one.__truediv__(2))

it works fine, giving 0.5 as the output.

What is happening here? I thought x / y called x.__truediv__(y).

Note: this is not just for division. It is happening for all "magic methods".

>Solution :

Magic methods are looked up on the class, not the individual object. Your Emulate class does not define Emulate.__truediv__, instead adding an instance attribute whose value is the method-wrapper found on the int value.

When you try to use one / 2, the lookup of Emulate.__truediv__ fails.

When you try to use one.__truediv__, the lookup of the instance attribute succeeds and produces a method wrapper that can be called with 2 as its argument, giving the observed result.

You can see this in the generated byte code:

>>> dis.dis('print(one/2)')
  1           0 LOAD_NAME                0 (print)
              2 LOAD_NAME                1 (one)
              4 LOAD_CONST               0 (2)
              6 BINARY_TRUE_DIVIDE
              8 CALL_FUNCTION            1
             10 RETURN_VALUE

Here, the opcode BINARY_TRUE_DIVIDE is what takes care of trying to find the necessary method using the type of the value referenced by one.

>>> dis.dis('print(one.__truediv__(2))')
  1           0 LOAD_NAME                0 (print)
              2 LOAD_NAME                1 (one)
              4 LOAD_METHOD              2 (__truediv__)
              6 LOAD_CONST               0 (2)
              8 CALL_METHOD              1
             10 CALL_FUNCTION            1
             12 RETURN_VALUE

Here, an explicit method lookup on the object one produces the value of the __truediv__ instance attribute you created.

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading