Re:PEP 572: Python assignment expressions has been accepted
by uryga on Tuesday July 03, 2018 @06:45AM
(#17449062)
> 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)
Re:PEP 572: Python assignment expressions has been accepted
by chriswarbo on Tuesday July 03, 2018 @09:02AM
(#17449776)
Hmm, 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'
Re:PEP 572: Python assignment expressions has been accepted
by bilboa on Tuesday July 03, 2018 @02:25PM
(#17452560)
This 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.
Re:PEP 572: Python assignment expressions has been accepted
by chriswarbo on Tuesday July 03, 2018 @03:23PM
(#17452949)
Yeah, 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 )
Re:PEP 572: Python assignment expressions has been accepted
by bilboa on Tuesday July 03, 2018 @05:28PM
(#17453736)
I found the official docs on how python special methods are looked up.
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.
You could, but that would turn "syntactic sugar" into a useless phrase with arbitrary meaning.
The phrase "syntactic sugar" is usually reserved for language constructs which can always be rewritten, in-place, to some other construct in the same language, such that the semantics is identical (i.e. we can't tell which construct was used, unless we parse the contents of the file).
Python has examples like `foo += bar` being sugar for `foo = foo + bar`.
As an aside, your mention of "machine language" implies the use of operational semantics. That's where we say the "meaning" of a program depends on what it does to the machine when executed. That's fine, but it's not the only approach to semantics. In particular denotational semantics defines the meaning of a program by giving a meaning to each syntactic element of the language and their combinations, usually by rewriting them into some other, well-defined language (e.g. set theory). I much prefer denotational semantics, since it lets me 'think in the language', rather than making me 'think like the machine'.