On 30 March 2018 at 21:16, Nathaniel Smith firstname.lastname@example.org wrote:
On Fri, Mar 30, 2018 at 3:29 AM, Serhiy Storchaka email@example.com wrote:
29.03.18 18:06, Terry Reedy пише:
On 3/28/2018 11:27 AM, Serhiy Storchaka wrote:
The optimizer already changes semantic. Non-optimized "if a and True:" would call bool(a) twice, but optimized code calls it only once.
Perhaps Ref 3.3.1 object.__bool__ entry, after " should return False or True.", should say something like "Should not have side-effects, as redundant bool calls may be optimized away (bool(bool(ob)) should have the same result as bool(ob))."
Do you meant that it should be idempotent operation? Because bool(bool(ob)) always have the same result as bool(ob)) if bool(ob) returns True or False.
And bool(obj) does always return True or False; if you define a __bool__ method that returns something else then bool rejects it and raises TypeError. So bool(bool(obj)) is already indistinguishable from bool(obj).
However, the naive implementation of 'if a and True:' doesn't call bool(bool(a)), it calls bool(a) twice, and this *is* distinguishable by user code, at least in principle.
>>> class FlipFlop: ... _state = False ... def __bool__(self): ... result = self._state ... self._state = not result ... return result ... >>> toggle = FlipFlop() >>> bool(toggle) False >>> bool(toggle) True >>> bool(toggle) False >>> bool(toggle) and bool(toggle) False >>> toggle and toggle <__main__.FlipFlop object at 0x7f35293604e0> >>> bool(toggle and toggle) True
So the general principle is that __bool__ implementations shouldn't do anything that will change the result of the next call to __bool__, or else weirdness is going to result.