3 ms·
> Python has examples like `foo += bar` being sugar for `foo = foo + bar`. Nitpick, but I don't think that's true – AFAIK they translate into different method
by uryga 8y ago
> Python has examples like `foo += bar` being sugar for `foo = foo + bar`.
Nitpick, but I don't think that's true – AFAIK they translate into different method calls.
`foo + bar` →`foo.__add__(bar)`
`foo += bar` → `foo.__iadd__(bar)`
(note the `i` in the second one)
- chriswarbo 8y agoHmm, good catch. Interestingly, I considered using `a + b` as sugar for `a.__add__(b)`, but rejected that because they're not quite equivalent. For example if `__add__` is defined using a magic method: >>> class A(object): ... def __getattribute__(self, attr): ... if attr == "__add__": ... return lambda *_: "hello world" ... return None ... >>> a = A() >>> a.__add__(A()) 'hello world' >>> a + A() Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: unsupported operand type(s) for +: 'A' and 'A'
- bilboa 8y agoThis is because the actual translation of `a + b` is a little more complicated. It's something like this: if '__add__' in a.__dict__: try: return a.__add__(b) except NotImplemented: if '__radd__' in b.__dict__: return b.__radd__(a) elif '__radd__' in b.__dict__: return b.__radd__(a) raise TypeError('unsupported operand type(s) for +: '{}' and '{}'.format(type(a), type(b)) In particular, the runtime seems to directly look for '__add__' in the object's __dict__, rather than just trying to invoke `__add__`, so your `__getattribute__` method isn't enough to make it work. If you add an actual `__add__` method to A your example will work.
- chriswarbo 8y agoYeah, I had a feeling the real 'expansion' would be more involved. I didn't know about the lookup in __dict__, that's good to know. I'm reminded of PHP, where (at least in version 5.*) we could write: $myObject->foo = function() { return "hello world"; }; $x = $myObject->foo; $x(); // Hello world $myObject->foo(); // Error: no such method 'foo' (Taken from an old comment https://news.ycombinator.com/item?id=8119419 https://news.ycombinator.com/item?id=8119419 )
- bilboa 8y agoI found the official docs on how python special methods are looked up. https://docs.python.org/3/reference/datamodel.html#special-lookup https://docs.python.org/3/reference/datamodel.html#special-l... Apparently the runtime is even more picky than I showed. The method has to be defined on the object's type, not in the object's instance dictionary. So, really the lookup is something like: if hasattr(type(a), '__add__'): The link I provided explains the rationale for bypassing the instance dictionary and `__getattribute__` method.