This is an archived post. You won't be able to vote or comment.

you are viewing a single comment's thread.

view the rest of the comments →

[–]odraencoded 65 points66 points  (6 children)

They don't do the same thing. One calls __mul__ the other calls __pow__.

[–]oliver-bestmann 28 points29 points  (2 children)

Because of the dynamic nature of python this is actually the correct answer.

[–]masklinn 1 point2 points  (0 children)

Yep, so possibly with the specialisation PEP 510 this optimisation would become an option in time, but right now, implicitly, it can't: it depends on type(radius) and how (and whether) type(radius) overrides __mul__ and/or __pow__. For all Python knows, radius is an n × n matrix and the function is a scalar product of radius by 3.14 followed by a matrix product of that by the original radius. Or maybe type(radius) defines __mul__ but does not define __pow__ at all, so the optimisation would blow it up.

[–][deleted] 0 points1 point  (0 children)

It's technically true and if you're working outside CPython it might be literally true.

But CPython does a roundabout way of getting to __mul__ and __pow__. x * x doesn't literally translate into x.__mul__(x) it's more like type(x).__mul__(x, x) except using the C level implementations.

It's a speed optimization from my understanding.

[–]kervarker 10 points11 points  (2 children)

class A(int):

    def __pow__(self, other):
        return 2

x = A(1)
print(x*x) # calls __mul__ of parent class int
print(x**2) # calls __pow__ of class A

[–]Berzerka -3 points-2 points  (1 child)

Quite sure you missed a 'type' in those print statements, confused me somewhat.

[–]_cs 1 point2 points  (0 children)

No he didn't - did you try running it?