pythonmagic-methods

Can I change the default __add__ method in Python?


Is it possible to change the default __add__ method to do something else than just add?

For example, if the goal is with this line: 5+5 get The answer is 10 or anything else like 0 by changing __add__ to be x-y instead of x+y?

I know I can change __add__ in my own classes:

class Vec():
    def __init__(self,x,y):
        self.x = x
        self.y = y
    
    def __repr__(self):
        return f'{self.x, self.y}'

    def __add__(self, other):
        self.x += other.x
        self.y += other.y
        return Vec(self.x,self.y)

    
v1 = Vec(1,2)
v2 = Vec(5,3)

v1+v2
# (6, 5)

Can I somehow target the default __add__ method to change its behaviour? I intuitively think that __add__ is defined in each default data type to return specific results, but then again, the __add__ method is what we address when changing it for a specific class, so, is it possible to change the main __add__ logic?

Something along these lines?

class __add__():
    ...

Solution

  • If you are looking for information about how the C level built-ins are defined you would want to look at some of the source code, note that I'm linking specifically to floats but the structure exists for all number types:

    static PyNumberMethods float_as_number = {
        float_add,          /* nb_add */
        float_sub,          /* nb_subtract */
        float_mul,          /* nb_multiply */
    

    this is the structure for all the C function pointers that implement number methods, (for floats in this case) each builtin type that defines any number related methods will define a PyNumberMethods structure, this is then used in the formal definition of the type:

    PyTypeObject PyFloat_Type = {
        PyVarObject_HEAD_INIT(&PyType_Type, 0)
        "float",
        sizeof(PyFloatObject),
       
        ...
            
        &float_as_number,                           /* tp_as_number */
    

    the PyTypeObject represents all the relevant information needed to construct the float object in python, (or equivalently, int or str etc.) containing all the methods, attributes, and necessary meta-data to work as a python type. So if you really wanted to change adding floats to instead do another well defined task you'd just change it to point to the other function:

    static PyNumberMethods float_as_number = {
        float_sub,          /* nb_add.  overrides to do subtraction because I want to break everything >:D */
        float_sub,          /* nb_subtract */
    
    

    If you wanted to write your own behaviour you could write your own function and point to it in this structure instead.