How Python chooses which object to use the method overload?
For example:
class a:
def __init__(self, other):
self.data = other
def __add__(self, other):
return self.data + other
def __radd__(self,other):
return self.data + other
X = a(1)
X+1
1+X
Why in X + 1 expression , calls a method __add__ in object at the left, and in expression 1 + X method __add__ is called at object on the right?
X+1
first, calls:
X.__add__(1)
That succeeds, so no further work is needed.
On the other hand, this:
1+X
calls
(1).__add__(X)
That fails because int doesn't know how to interface with a class a. "As a last resort" this is tried instead:
X.__radd__(1)
From the docs on __radd__:
These functions are only called if the left operand does not support the corresponding operation and the operands are of different types.
Related
I want to subclass from float but don't want it to init soon. I also don't want to explicitly call float() for my object.
For example, I don't want to calculate anything before it is required. I want only to do an object that behaves like float. Here is how I want to create class:
class MassiveAverage(float):
def __init__(self, floats: list[float]):
self.floats = floats
def __float__(self) -> float:
return sum(self.floats) / len(self.floats)
And this is how I want to use it:
massive_average = MassiveAverage([1.1, 2.2]) # no any calculations
massive_sum = massive_average * 2 # this is were it calculates its float value
For the answer to this question I am going to assume you are already familiar with python's "magic methods". #gftea's answer has a link to the documentation for some of the magic methods if you are not familiar.
You are going to have to manually define each "magic function" __mul__, __add__, __sub__, etc.
class MassiveAverage:
def __init__(self, floats):
self._avg = sum(floats)/len(floats)
def __mul__(self, other):
return self._avg * other
def __sub__(self, other):
return self._avg - other
def __add__(self, other):
return self._avg + other
...
But, this doesn't handle your lazy evaluation use case. Instead, we could maintain an internal cache, and on the first time one of these magic methods are evaluated, we could run the average function.
class MassiveAverage:
def __init__(self, floats):
self._floats = floats
self._avg = None
#property
def avg(self):
if self._avg is None:
self._avg = sum(self._floats) / len(self._floats)
return self._avg
Then, we can replace our magic functions and use self.avg.
def __mul__(self, other):
return self.avg * other
def __add__(self, other):
return self.avg + other
def __sub__(self, other):
return self.avg - other
...
Unfortunately, you cannot subclass float in the manner you want. Because you are specifying lazy evaluation, you are fundamentally changing how the methods in the float class work (since they don't need lazy evaluation). You would still have to manually change each magic method.
you should overwrite the operator, for example, to overwrite *, you can overwrite the __mul__ method
def __mul__(self, float): ...
see below for methods can be defined to emulate numeric objects
https://docs.python.org/3/reference/datamodel.html?highlight=rmul#emulating-numeric-types
__float__ is used for exactly one purpose: to define the behavior of float(x) as x.__float__(). There is no implicit conversion in an expression like massive_average * 2. This could mean any number of things:
massive_average.__int__() * 2
massive_average.__float__() * 2
massive_average.__complex__() * 2
massive_avarge.__str__() * 2
so Python refuses to guess. It will try massive_average.__mul__(2), and failing that, (2).__rmul__(massive_average), before giving up.
Each of the type-specific "conversion" methods are used only by the corresponding type itself. print, for example, does not call __str__ (directly); it only is defined to call str on each of its arguments, and str takes care of calling __str__.
I'm currently learning python operator overloading (__radd__ and __add__ to be exact) and I have the following code
class Commuter1:
def __init__(self, val):
self.val = val
def __add__(self, other):
print('add', self.val, other)
return self.val + other
def __radd__(self, other):
print('radd', self.val, other)
return other + self.val
x = Commuter1(88)
y = Commuter1(99)
print(x + y)
I have got the following result
When used separately, I understand how __radd__ and __add__ works. But for the line x + y, I'm not sure why both __radd__ and __add__ methods are evoked.
First, Python looks at the types of x and y to decide whether to call x.__add__ or y.__radd__. Since they're both the same type Commuter1, it tries x.__add__ first.
Then, inside your __add__ method, you do this:
return self.val + other
So, Python looks at the types of self.val and other to decide whether to call self.val.__add__ or other.__radd__. Since they're unrelated types int and Commuter1, it tries int.__add__ first.
But int.__add__ returns NotImplemented for a type it doesn't know about, so Python falls back to calling other.__radd__.
Inside your __radd__ method, you do this:
return other + self.val
So, Python looks at the types of other and self.val to decide whether to call other.__add__ or self.val.__radd__. Since they both the same type int, it tries __add__ first.
And of course int.__add__ works on another int, so it returns a value for the inner + inside your __radd__, which you return, which returns a value for the + inside __add__, which you return, which returns a value for the top-level +, which you print.
I have a class called Time, and I need to implement a Frequency class. How can I implement dividing ints or floats by an instance of Time to get an instance of Frequency ?
I already know about __div__, __truediv__, __floordiv__ and other Python special methods, and I already use them in my code to divide instances of classes by numbers or instances of other classes, but I cannot find a way to divide a number by an instance of my class.
Is it possible to implement dividing a number by an instance of a class in Python ?
The __rtruediv__ method is what you're looking for.
When x / y is executed, if type(x) does not implement a __div__(self, other) method where other can be of class type(y), then type(y).__rtruediv__(y, x) is executed, and its result is returned.
Usage:
class Foo:
def __init__(self, x):
self.x = x
def __truediv__(self, other):
return self.x / other
def __rtruediv__(self, other):
return other / self.x
>>> f = Foo(10)
>>> f / 10
1.0
>>> 10 / f
1.0
Yes. You just have to make sure that Time.__rtruediv__() returns a Frequency instance when it receives a float or integer.
Usage:
>>> 100 / Time(2)
Frequency(50.0)
>>> 2.5 / Time(5)
Frequency(0.5)
Implementation:
class Time:
def __init__(self, value):
self.value = value
def __rtruediv__(self, other):
if not isinstance(other, (int, float)):
return NotImplemented
return Frequency(other / self.value)
class Frequency:
def __init__(self, value):
self.value = value
def __repr__(self):
return '{}({})'.format(self.__class__.__name__, self.value)
The python docs contains a full example on implementing the arithmetic operations for your custom classes.
The proper way to handle incompatible types is to return the special value NotImplemented.
NotImplemented
Special value which should be returned by the binary
special methods (e.g. __eq__(), __lt__(), __add__(), __rsub__(), etc.)
to indicate that the operation is not implemented with respect to the
other type
Suppose you try to use a unsupported complex number, returning NotImplemented will eventually cause a TypeError with a correct error message. (at least in python 3)
>>> 100j / Time(2)
Traceback (most recent call last):
File "python", line 1, in <module>
TypeError: unsupported operand type(s) for /: 'complex' and 'Time'
you need to implement __rtruediv__ and__rfloordiv__.
from the documentation
object.__radd__(self, other)
object.__rsub__(self, other)
object.__rmul__(self, other)
object.__rmatmul__(self, other)
object.__rtruediv__(self, other)
object.__rfloordiv__(self, other)
object.__rmod__(self, other)
object.__rdivmod__(self, other)
object.__rpow__(self, other)
object.__rlshift__(self, other)
object.__rrshift__(self, other)
object.__rand__(self, other)
object.__rxor__(self, other)
object.__ror__(self, other)
These methods are called to implement the binary arithmetic operations
(+, -, *, #, /, //, %, divmod(), pow(), **, <<, >>, &, ^, |) with
reflected (swapped) operands. These functions are only called if the
left operand does not support the corresponding operation [3] and the
operands are of different types. [4] For instance, to evaluate the
expression x - y, where y is an instance of a class that has an
__rsub__() method, y.__rsub__(x) is called if x.__sub__(y) returns NotImplemented.
So, I've got a custom class that has a __mul__ function which works with ints. However, in my program (in libraries), it's getting called the other way around, i.e., 2 * x where x is of my class. Is there a way I can have it use my __mul__ function for this?
Just add the following to the class definition and you should be good to go:
__rmul__ = __mul__
Implement __rmul__ as well.
class Foo(object):
def __mul__(self, other):
print '__mul__'
return other
def __rmul__(self, other):
print '__rmul__'
return other
x = Foo()
2 * x # __rmul__
x * 2 # __mul__
I have never handled reverse operators before. I just finished learning about them so wanted to try them out. But for some reason, it is not working. Here is the code:
>>> class Subtract(object):
def __init__(self, number):
self.number = number
def __rsub__(self, other):
return self.number - other.number
>>> x = Subtract(5)
>>> y = Subtract(10)
>>> x - y # FAILS!
Traceback (most recent call last):
File "<pyshell#8>", line 1, in <module>
x - y
TypeError: unsupported operand type(s) for -: 'Subtract' and 'Subtract'
>>> x.__rsub__(y) # WORKS!
-5
If I change __rsub__ to __sub__, it works.
What am I doing wrong? Also what is the purpose of these reverse operators?
__rsub__() will only be called if the operands are of different types; when they're of the same type it's assumed that if __sub__ isn't present they can't be subtracted.
Also note that your logic is reversed in any case; you're returning self - other instead of other - self
The point of these methods is to allow this:
class MyNumber(object):
def __init__(self, x):
self.x = x
print 10 - MyNumber(9) # fails because 10.__sub__(MyNumber(9)) is unknown
class MyFixedNumber(MyNumber):
def __rsub__(self, other):
return MyNumber( other - self.x )
print 10 - MyFixedNumber(9) # MyFixedNumber(9).__rsub__(10) is defined
Very rarely useful though, usually you just use things of the same type and the direct __sub__
From Python's Data model at http://docs.python.org/reference/datamodel.html :
These methods are called to implement
the binary arithmetic operations (+,
-, *, /, %, divmod(), pow(), **, <<, >>, &, ^, |) with reflected (swapped) operands. These functions are only
called if the left operand does not
support the corresponding operation
and the operands are of different
types. [2] For instance, to evaluate
the expression x - y, where y is an
instance of a class that has an
__rsub__() method, y.__rsub__(x) is called if x.__sub__(y) returns
NotImplemented.
However - both objects must not be of the same class - that means, that even if you put a __sub__ method returning NotImplemented on your example above, you will still get the same error: Python just assumes your Subtract class can't subtract from "Subtract" iobjects, no matter the order.
However, this works:
class Sub1(object):
number = 5
def __sub__(self, other):
return NotImplemented
class Sub2(object):
number = 2
def __rsub__(self, other):
return other.number - self.number
a = Sub1()
b = Sub2()
print a - b
The methods with reflected operands are provided so that your class can implement an operator when the left operand is a primitive or something else that isn't under your control:
These functions are only called if the left operand does not support the corresponding operation and the operands are of different types.
Since they're both of the same type, it's cowardly refusing and you should implement the __sub__ method.