summing integer and class
Hi. Example test.py: class A(): def __add__(self, var): print("I'm in A class") return 5 a = A() a+1 1+a Execution: python test.py I'm in A class Traceback (most recent call last): File "../../test.py", line 7, in <module> 1+a TypeError: unsupported operand type(s) for +: 'int' and 'instance' So adding integer to class works fine, but adding class to integer fails. I could not understand why it happens. In objects/abstact.c we have the following function: static PyObject * binary_op1(PyObject *v, PyObject *w, const int op_slot) { PyObject *x; binaryfunc slotv = NULL; binaryfunc slotw = NULL; if (v->ob_type->tp_as_number != NULL) slotv = NB_BINOP(v->ob_type->tp_as_number, op_slot); if (w->ob_type != v->ob_type && w->ob_type->tp_as_number != NULL) { slotw = NB_BINOP(w->ob_type->tp_as_number, op_slot); if (slotw == slotv) slotw = NULL; } if (slotv) { if (slotw && PyType_IsSubtype(w->ob_type, v->ob_type)) { x = slotw(v, w); if (x != Py_NotImplemented) return x; Py_DECREF(x); /* can't do it */ slotw = NULL; } x = slotv(v, w); if (x != Py_NotImplemented) return x; Py_DECREF(x); /* can't do it */ } if (slotw) { x = slotw(v, w); if (x != Py_NotImplemented) return x; Py_DECREF(x); /* can't do it */ } Py_RETURN_NOTIMPLEMENTED; } When we adding class to integer we have both slotv and slotw. x = slotv(v, w); -> returns Py_NotImplemented. But in this case we should execute x = slotw(v, w); and function should be completed in the same way as when we adding integer to class. Can someone advise please where I mistake. -- thanks, Igor Vasilyev
On 2013-10-03, at 15:45 , Igor Vasilyev wrote:
Hi.
Example test.py:
class A(): def __add__(self, var): print("I'm in A class") return 5 a = A() a+1 1+a
Execution: python test.py I'm in A class Traceback (most recent call last): File "../../test.py", line 7, in <module> 1+a TypeError: unsupported operand type(s) for +: 'int' and 'instance'
So adding integer to class works fine, but adding class to integer fails. I could not understand why it happens. In objects/abstact.c we have the following function:
python-dev is about developing Python itself, not about developing in Python, so that's the wrong mailing list for these kinds of question. But FWIW the answer is that Python first tries 1.__add__(a), when that fails (with NotImplemented) it uses the reflected method[0] which is a.__radd__(1). Since that does not exist, the operation is invalid. [0] http://docs.python.org/2/reference/datamodel.html#object.__radd__
This list is for development OF Python, not for development in python. For
that reason, I will redirect this to python-list as well. My actual answer
is below.
On Thu, Oct 3, 2013 at 6:45 AM, Igor Vasilyev
Hi.
Example test.py:
class A(): def __add__(self, var): print("I'm in A class") return 5 a = A() a+1 1+a
Execution: python test.py I'm in A class Traceback (most recent call last): File "../../test.py", line 7, in <module> 1+a TypeError: unsupported operand type(s) for +: 'int' and 'instance'
So adding integer to class works fine, but adding class to integer fails. I could not understand why it happens. In objects/abstact.c we have the following function:
Based on the code you provided, you are only overloading the __add__ operator, which is only called when an "A" is added to something else, not when something is added to an "A". You can also override the __radd__ method to perform the swapped addition. See http://docs.python.org/2/reference/datamodel.html#object.__radd__ for the documentation (it is just below the entry on __add__). Note that for many simple cases, you could define just a single function, which then is defined as both the __add__ and __radd__ operator. For example, you could modify your "A" sample class to look like: class A(): def __add__(self, var): print("I'm in A") return 5 __radd__ = __add__ Which will produce:
a = A() a + 1 I'm in A 5 1 + a I'm in A 5
Chris
Igor Vasilyev wrote:
class A(): def __add__(self, var): print("I'm in A class") return 5 a = A() a+1 1+a
Execution: python test.py I'm in A class Traceback (most recent call last): File "../../test.py", line 7, in <module> 1+a TypeError: unsupported operand type(s) for +: 'int' and 'instance'
You need to define an __radd__ method for it to work as a right-hand operand.
When we adding class to integer we have both slotv and slotw. x = slotv(v, w); -> returns Py_NotImplemented. But in this case we should execute x = slotw(v, w);
Yes, but the wrapper that gets put in the type slot calls __rxxx__ instead of __xxx__ if it's being called for the right-hand operand. -- Greg
участники (4)
-
Chris Kaynor
-
Greg Ewing
-
Igor Vasilyev
-
Xavier Morel