Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Assigning vs. Defining Python Magic Methods

Consider the following abhorrent class:

class MapInt:
    __call__ = int

    def __sub__(self, other):
        return map(self, other)

    __add__ = map

One can then call map(int, lst) via MapInt() - lst, i.e.

assert list(MapInt() - ['1','2','3'])) == [1,2,3]    # passes

However, addition is not so cooperative:

assert list(MapInt() + ['1','2','3'])) == [1,2,3]    # TypeError: map() must have at least two arguments.

This strangeness can be resolve by invoking the magic method directly:

assert list(MapInt.__add__(MapInt(), ['1','2','3']))   == [1,2,3]    # passes
assert list(MapInt().__add__(MapInt(), ['1','2','3'])) == [1,2,3]    # passes

So my question is, what gives? Assigning __add__ directly seems to "discard" the self argument, but invoking the method itself or defining it in the standard way works fine.

like image 402
kg583 Avatar asked Sep 12 '25 13:09

kg583


1 Answers

The transformation of instance methods is described in the Python Data Model (emphasis mine):

Note that the transformation from function object to instance method object happens each time the attribute is retrieved from the instance [...] Also notice that this transformation only happens for user-defined functions; other callable objects (and all non-callable objects) are retrieved without transformation.

Since map is a built-in, not a user-defined function, there is no transformation to an instance method, so the self argument is not added.

like image 113
sj95126 Avatar answered Sep 15 '25 05:09

sj95126



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!