Issue846564
This issue tracker has been migrated to GitHub,
and is currently read-only.
For more information,
see the GitHub FAQs in the Python's Developer Guide.
Created on 2003-11-21 13:08 by amaury.forgeotdarc, last changed 2022-04-11 14:56 by admin. This issue is now closed.
Files | ||||
---|---|---|---|---|
File name | Uploaded | Description | Edit | |
nonzero.py | amaury.forgeotdarc, 2003-11-24 08:40 | script showing that "if a and b" can be broken. | ||
nonzero.py | amaury.forgeotdarc, 2003-11-24 08:41 | script showing that "if a and b" can be broken. |
Messages (7) | |||
---|---|---|---|
msg19068 - (view) | Author: Amaury Forgeot d'Arc (amaury.forgeotdarc) * | Date: 2003-11-21 13:08 | |
When the first operand of "and" results in False, its truth value is calculated again. Example: class myBool: def __init__(self,value): self.value = value def __nonzero__(self): print 'testing myBool(%s)' % self.value return bool(self.value) if myBool(0) and myBool(1): pass will print: testing myBool(0) testing myBool(0) The same thing occurs with the "or" operator, when the first argument has a True truth value: if myBool(2) and myBool(3): pass will print: testing myBool(2) testing myBool(2) This can be a problem when the "__nonzero__" function is slow or has side-effects. I agree this is not often the case... But imagine an object which truth value means "there are more data to read in a stream". If python evaluates __nonzero__ twice, the expression: "stream and otherTest()" can become True *without* evaluating the otherTest! |
|||
msg19069 - (view) | Author: Neal Norwitz (nnorwitz) * | Date: 2003-11-21 19:07 | |
Logged In: YES user_id=33168 Ouch! This happens in 2.2 and CVS (I assume 2.3 too). I'll look into this. Fixing this should be a good way to improve performance. :-) Thanks for the report! |
|||
msg19070 - (view) | Author: Tim Peters (tim.peters) * | Date: 2003-11-21 19:29 | |
Logged In: YES user_id=31435 Don't panic <wink>. "and" doesn't evaluate anything twice. The subtlety here is that "and" and "or" return one of their arguments. If x evaluates to false in "x and y", then "x and y" returns x: >>> class C: ... def __nonzero__(self): return False ... >>> x, y = C(), C() >>> (x and y) is x True >>> (x or y) is y True >>> The second evaluation occurs because "if expr:" has to evaluate expr. That part's got nothing to do with "and", it's entirely to do with "if". None of this is going to change, of course. |
|||
msg19071 - (view) | Author: Amaury Forgeot d'Arc (amaury.forgeotdarc) * | Date: 2003-11-24 08:40 | |
Logged In: YES user_id=389140 I don't mind the __nonzero__ be called twice, but the test can be totally wrong if the value truth changes: import random class C: def __nonzero__(self): return bool(random.randint(0,1)) if C() and False: print "Should we really allow this?" There are 25% chances for the condition to be true. I find this odd. OK, this kind of script is not likely to happen in real life. So I attached a script where the object is a kind of pipe; it is True if there are data in it. And while we only fill it with "1", we sometimes enter the block where a "2" is found! If this behaviour is expected, it should at least be clearly documented! This remind me the macros in C, where a "variable" can be evaluated several times, so we have to be aware of side- effects. I did not know that "if a and b" was such a macro... |
|||
msg19072 - (view) | Author: Amaury Forgeot d'Arc (amaury.forgeotdarc) * | Date: 2003-11-24 08:41 | |
Logged In: YES user_id=389140 I don't mind the __nonzero__ be called twice, but the test can be totally wrong if the value truth changes: import random class C: def __nonzero__(self): return bool(random.randint(0,1)) if C() and False: print "Should we really allow this?" There are 25% chances for the condition to be true. I find this odd. OK, this kind of script is not likely to happen in real life. So I attached a script where the object is a kind of pipe; it is True if there are data in it. And while we only fill it with "1", we sometimes enter the block where a "2" is found! If this behaviour is expected, it should at least be clearly documented! This remind me the macros in C, where a "variable" can be evaluated several times, so we have to be aware of side- effects. I did not know that "if a and b" was such a macro... |
|||
msg19073 - (view) | Author: Martin v. Löwis (loewis) * | Date: 2003-11-24 22:28 | |
Logged In: YES user_id=21627 This is clearly not a bug. I'm closing it as "works for me": the "and" operator does *not* evaluate its argument twice (as Tim explains, and in contrast to what the subject claims). That the semantics of the if statement (*not* the "and" expression) is surprising if the result of __nonzero__ changes in subsequent invokcations might be a fact (strictly speaking, whether you are surprised depends on what you expect). However, the behaviour of Python is not at all random in itself, and there are very good reasons for things being just the way they are. If changing zero-ness of objects surprises you: Don't do that, then. |
|||
msg19074 - (view) | Author: Tim Peters (tim.peters) * | Date: 2003-11-24 22:34 | |
Logged In: YES user_id=31435 Just noting that someone who creates objects with insanely surprising __nonzero__ behavior can easily avoid the "double evaluation" by coding if bool(x) and bool(y): instead. I agree with Martin that there's no bug here, so agree with his closing the bug report. |
History | |||
---|---|---|---|
Date | User | Action | Args |
2022-04-11 14:56:01 | admin | set | github: 39578 |
2003-11-21 13:08:39 | amaury.forgeotdarc | create |