[ python-Bugs-846564 ] "and" operator tests the first argument twice

SourceForge.net noreply at sourceforge.net
Mon Nov 24 03:40:35 EST 2003


Bugs item #846564, was opened at 2003-11-21 14:08
Message generated for change (Comment added) made by amauryf
You can respond by visiting: 
https://sourceforge.net/tracker/?func=detail&atid=105470&aid=846564&group_id=5470

Category: Python Interpreter Core
Group: None
Status: Open
Resolution: None
Priority: 5
Submitted By: Amaury Forgeot d'Arc (amauryf)
Assigned to: Nobody/Anonymous (nobody)
Summary: "and" operator tests the first argument twice

Initial Comment:
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!

----------------------------------------------------------------------

>Comment By: Amaury Forgeot d'Arc (amauryf)
Date: 2003-11-24 09:40

Message:
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...

----------------------------------------------------------------------

Comment By: Tim Peters (tim_one)
Date: 2003-11-21 20:29

Message:
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.

----------------------------------------------------------------------

Comment By: Neal Norwitz (nnorwitz)
Date: 2003-11-21 20:07

Message:
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!

----------------------------------------------------------------------

You can respond by visiting: 
https://sourceforge.net/tracker/?func=detail&atid=105470&aid=846564&group_id=5470



More information about the Python-bugs-list mailing list