class C(object):
def __init__(self, value):
self.value = value
def __add__(self, other):
if isinstance(other, C):
return self.value + other.value
if isinstance(other, Number):
return self.value + other
raise Exception("error")
c = C(123)
print c + c
print c + 2
print 2 + c
obviously, the first two print statements will work and the third one fails because int.add() cannot deal with a class C instance.
246
125
print 2 + c
TypeError: unsupported operand type(s) for +: 'int' and 'C'
Is there a way to get around this, so 2+c will cause C.add() to be called?
You need to add __radd__ as well to handle the reverse case:
def __radd__(self, other):
if isinstance(other, C):
return other.value + self.value
if isinstance(other, Number):
return other + self.value
return NotImplemented
and note that you should not raise an exception; return the NotImplemented singleton instead. That way the other object could still try to support __add__ or __radd__ for your object and would be given a chance to implement addition too.
When you try to add two types a and b, Python first tries to call a.__add__(b); if that call returns NotImplemented, b.__radd__(a) is attempted instead.
Demo:
>>> from numbers import Number
>>> class C(object):
... def __init__(self, value):
... self.value = value
... def __add__(self, other):
... print '__add__ called'
... if isinstance(other, C):
... return self.value + other.value
... if isinstance(other, Number):
... return self.value + other
... return NotImplemented
... def __radd__(self, other):
... print '__radd__ called'
... if isinstance(other, C):
... return other.value + self.value
... if isinstance(other, Number):
... return other + self.value
... return NotImplemented
...
>>> c = C(123)
>>> c + c
__add__ called
246
>>> c + 2
__add__ called
125
>>> 2 .__add__(c)
NotImplemented
>>> 2 + c
__radd__ called
125
You need to implement __radd__ on the class.
def __radd__(self, other):
return self.value + other
This gets called automatically, since the int class will raise a NotImplemented error
Related
I have a class it can successfully add two variables of object of class a
class a():
def __add__(self, other):
return self.val+other.val
def __init__(self,a):
self.val=a
aa=a(22)
bb=a(11)
aa+bb
33
But when I try to give it third object to add, it through error
cc=a(11)
aa+bb+cc
Traceback (most recent call last):
File "<pyshell#43>", line 1, in <module>
aa+bb+cc
TypeError: unsupported operand type(s) for +: 'int' and 'a'
It is because first two aa+bb return int and its add function is design to add object addition
Any one can suggest how I can add three objects
I find this link Using __add__ operator with multiple arguments in Python but it is working on one object and 2 integers. But I want to add three objects. and all these three combine and return integer
__add__ must return an instance of a class, not int
class a():
def __add__(self, other):
return a(self.val + other.val)
def __init__(self, a):
self.val = a
Here's an example of how __add__ and __radd__ should be implemented.
We have a class A that has an attribute n which is an integer. We want to be able to add classes of the same type and we also want to be able to add integer values. Therefore:
class A:
def __init__(self, n):
self._n = n
#property
def n(self):
return self._n
def __add__ (self, other):
if isinstance(other, int):
return A(self.n + other)
assert isinstance(other, type(self))
return A(self.n + other.n)
def __radd__(self, other):
assert isinstance(other, int)
return A(self.n + other)
def __str__(self):
return f'{self.n}'
def __repr__(self):
return f'{self.n=}'
a = A(1)
b = A(2)
c = A(3)
print(10+a+10+b+10+c+10)
c += 5
print(c)
print(c.n)
Output:
46
8
8
This is what I looking for
class a():
def __add__(self, other):
return a(self.val+other.val)
def __init__(self,a):
self.val=a
aa=a(22)
bb=a(11)
cc=a(11)
d=aa+bb+cc
print(d.val)
Out put
44
I have a class with the following structure:
class Example:
def __init__(self, value, foo):
self.value = value
self.foo = foo
self.bar = self.modify_stuff(value, foo)
def modify_stuff(self, value, foo):
""" some code """
pass
I want to create an instance of the class, and then be able to refer to value directly, like this:
ex = Example(3, 'foo')
ans = 5 + ex
Instead of:
ans = 5 + ex.value
How can I do this?
Rewrite the add and radd:
class Example:
def __init__(self, value):
self.value = value
def __add__(self, other):
if isinstance(other, Example):
return self.value + other.value
return self.value + other
def __radd__(self, other):
if isinstance(other, Example):
return self.value + other.value
return self.value + other
print(Example(3) + 5)
print(Example(4) + Example(2))
# 8
# 6
I'm just trying to make an Enum in Python 3 by reference of the official Python docs https://docs.python.org/3.4/library/enum.html and specifically 8.13.13.2 and 8.13.13.4 examples.
My target is having an Enum which I can iterate, compare and also having three separate attributes. But I keep finding this error:
AttributeError: can't set attribute
It seems an error in __init__() constructor.
Code:
I tried firstly with one only class like this:
class Hand(Enum):
FIVE_OF_KIND = (6,'FIVE_OF_KIND',[5])
FOUR_OF_KIND = (5,'FOUR_OF_KIND',[4,1])
FULL_HOUSE = (4,'FULL_HOUSE',[3,2])
THREE_OF_KIND = (3,'THREE_OF_KIND',[3,1,1])
DOUBLE_PAIR = (2,'DOUBLE_PAIR',[2,2,1])
PAIR = (1,'PAIR',[2,1,1,1])
NOTHING = (0,'NOTHING',[1,1,1,1,1])
def __init__(self, val, name, struct):
self.val = val
self.name = name
self.struct = struct
def __ge__(self, other):
if self.__class__ is other.__class__:
return self.value >= other.value
return NotImplemented
def __gt__(self, other):
if self.__class__ is other.__class__:
return self.value > other.value
return NotImplemented
def __le__(self, other):
if self.__class__ is other.__class__:
return self.value <= other.value
return NotImplemented
def __lt__(self, other):
if self.__class__ is other.__class__:
return self.value < other.value
return NotImplemented
and secondly with two classes like this:
class OrderedEnum(Enum):
def __ge__(self, other):
if self.__class__ is other.__class__:
return self.value >= other.value
return NotImplemented
def __gt__(self, other):
if self.__class__ is other.__class__:
return self.value > other.value
return NotImplemented
def __le__(self, other):
if self.__class__ is other.__class__:
return self.value <= other.value
return NotImplemented
def __lt__(self, other):
if self.__class__ is other.__class__:
return self.value < other.value
return NotImplemented
class Hand(OrderedEnum):
FIVE_OF_KIND = (6,'FIVE_OF_KIND',[5])
FOUR_OF_KIND = (5,'FOUR_OF_KIND',[4,1])
FULL_HOUSE = (4,'FULL_HOUSE',[3,2])
THREE_OF_KIND = (3,'THREE_OF_KIND',[3,1,1])
DOUBLE_PAIR = (2,'DOUBLE_PAIR',[2,2,1])
PAIR = (1,'PAIR',[2,1,1,1])
NOTHING = (0,'NOTHING',[1,1,1,1,1])
def __init__(self, val, name, struct):
self.val = val
self.name = name
self.struct = struct
Enum objects already have a name attribute (for example, see 8.13.13.3), and apparently you are not allowed to set it – which makes sense when you think about how an enum should behave. You can achieve what you want like this:
from enum import Enum
class OrderedEnum(Enum):
# Same as your code.
class Hand(OrderedEnum):
FIVE_OF_KIND = (6, [5])
FOUR_OF_KIND = (5, [4,1])
FULL_HOUSE = (4, [3,2])
THREE_OF_KIND = (3, [3,1,1])
DOUBLE_PAIR = (2, [2,2,1])
PAIR = (1, [2,1,1,1])
NOTHING = (0, [1,1,1,1,1])
def __init__(self, val, struct):
# No need to set self.name. It's already handled.
self.val = val
self.struct = struct
for h in Hand:
print((h.name, h.val, h.struct))
In Python, data types (like int, float) both represent a value, but also have some built-in attributes/functions/etc:
In [1]: a = 1.2
In [2]: a
Out[2]: 1.2
In [3]: a.is_integer()
Out[3]: False
Is it possible to reproduce this behavior within Python, e.g. define a class:
class Scalar:
def __init__(self, value)
self.value = value
# other code ....
s = Scalar(1.2)
where I could have s return 1.2 (instead of typing s.value), and do things like a = s -> a = 1.2? The closest I can get to this behavior is adding something like:
def __getitem__(self, key=None):
return self.value
and using a = s[()], but that doesn't look very good.
where I could have s return 1.2 (instead of typing s.value)
In the console? Then implement the __repr__ method.
a = s -> a = 1.2
To avoid having to use a = s.value, you can implement __call__ and call the object:
>>> class Scalar:
... def __init__(self, value):
... self.value = value
... def __repr__(self):
... return str(self.value)
... def __call__(self):
... return self.value
...
>>> s = Scalar(1.2)
>>> s
1.2
>>> a = s()
>>> a
1.2
Check the documentation about the data model on emulating numeric types.
For example:
class Scalar:
def __init__(self, value):
self.value = value
def __repr__(self):
return str(self.value)
def __call__(self):
return self.value
def __add__(self, other):
return Scalar(self.value + other.value)
def __lt__(self, other):
return self.value < other.value
def ___le__(self, other):
return self.value <= other.value
def __eq__(self, other):
return self.value == other.value
def __ne__(self, other):
return self.value != other.value
def __gt__(self, other):
return self.value > other.value
def __ge__(self, other):
return self.value >= other.value
Can be used like this:
>>> s1 = Scalar(1.2)
>>> s2 = Scalar(2.1)
>>> s1 + s2
3.3
>>> s1 < s2
True
>>> s1 > s2
False
>>> s1 != s2
True
>>> s1 <= s2
True
>>> s1 >= s2
False
There are also the __int__ and __float__ magic methods, which you can implement and use like this (this is more semantically correct):
>>> a = int(s)
>>> a = float(s)
As far as I know, that's not possible for your a = s example. You would have to change the behavior of =, the assignment operator. The assignment operator doesn't really do anything to the object on the right, it just copies a reference to it (in the case of an object, at least).
In general, it is possible to change the behavior of built in operators for your custom classes using operator overloading, but Python doesn't provide this sort of option for assignment (=) because of how different it is from operators like addition (+) and even equality (==).
I have a class foo that is essentially a float with some extra attributes attached. I can overwrite its __sub__ method so that I can do subtraction one direction, but I can't figure out how to do it the other way:
class foo():
def __init__(self, value, otherstuff):
self.value = value
self.otherstuff = otherstuff
def __sub__(self, other):
return self.value - other
a = 5
b = foo(12, 'blue')
print b-a # this works fine and returns 7
print a-b # I want this to return -7 but it obviously doesn't work
Is there a way to do this?
A general solution for add, sub, mul, div would be ideal, but sub and div are most pressing since they're not reversible.
You just need to override __rsub__, for right-hand side subtraction:
class foo():
def __init__(self, value, otherstuff):
self.value = value
self.otherstuff = otherstuff
def __sub__(self, other):
return self.value - other
def __rsub__(self, other):
return other - self.value
Output:
print(b - a)
7
print(a - b)
-7
There are similar methods like __radd__, __rmul__ for other operations.