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

SourceForge.net noreply at sourceforge.net
Mon Nov 24 17:28:23 EST 2003


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

Category: Python Interpreter Core
>Group: Not a Bug
>Status: Closed
>Resolution: Invalid
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: Martin v. Löwis (loewis)
Date: 2003-11-24 23:28

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

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

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

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