[Numpy-discussion] logical priority

Fernando Perez Fernando.Perez at colorado.edu
Tue Feb 8 17:14:29 CST 2005

Stephen Walton wrote:
> Fernando Perez wrote:
>>Travis Oliphant wrote:
>>>Currently, I don't think Python allows "over-riding" the "and" operation.
>>You are correct:
> What I want must be possible somehow, though:
> In [6]: a=[True,False]
> In [7]: b=[False,False]
> In [8]: a and b
> Out[8]: [False, False]
> In [9]: a or b
> Out[9]: [True, False]
> In [10]: not a
> Out[10]: False
> So, standard Python does apply logical "and" and "or", but not "not", 
> element by element to a list or tuple of booleans.  Is there no way to 
> get access to this for a numarray bool array?  Can we get Guido to 
> change "not" to also operate element-wise on a list of booleans?

I think you are misunderstanding something.  Python does not "apply logical 
"and" and "or", but not "not",  element by element to a list or tuple of 
booleans", as you say.  Look again at the decompiled bytecode:

In [2]: dis.dis(compile('a and b','<>','eval'))
   0           0 LOAD_NAME                0 (a)
               3 JUMP_IF_FALSE            4 (to 10)
               6 POP_TOP
               7 LOAD_NAME                1 (b)
         >>   10 RETURN_VALUE

What it does is execute the JUMP_IF_FALSE bytecode, which is mapped to the 
__nonzero__ special method.  From http://docs.python.org/ref/customization.html:

__nonzero__(  	self)
     Called to implement truth value testing, and the built-in operation 
bool(); should return False or True, or their integer equivalents 0 or 1. When 
this method is not defined, __len__() is called, if it is defined (see below). 
If a class defines neither __len__() nor __nonzero__(), all its instances are 
considered true.

Now, lists don't actually have this method, so a call to __len__ is made, and 
any non-empty list is considered true.  The return value is then whatever is 
on the stack, which will be either be a, or b if a tested false:

In [6]: a
Out[6]: [True, False]

In [7]: a and 0
Out[7]: 0

In [8]: a and 1
Out[8]: 1

In [9]: a and 'hello'
Out[9]: 'hello'

The point is that and/or only operate on one operand at a time, with unary 
functions/methods.  They do NOT call a binary function, the way & does:

In [5]: dis.dis(compile('a & b','<>','eval'))
   0           0 LOAD_NAME                0 (a)
               3 LOAD_NAME                1 (b)
               6 BINARY_AND
               7 RETURN_VALUE

This means that certain things which can be done with & are fundamentally 
impossible with 'and', since you never have both arguments in your hands at 
the same time.

Bytecode analysis can be really useful to understand this kind of subtle 
issues.  I can't think of any language where this approach is as easy to do 
and friendly as in python.



More information about the Numpy-discussion mailing list