"0 in [True,False]" returns True

Antoon Pardon apardon at forel.vub.ac.be
Tue Dec 13 06:29:10 EST 2005


Op 2005-12-13, Steve Holden schreef <steve at holdenweb.com>:
> Antoon Pardon wrote:
>> Op 2005-12-13, Steve Holden schreef <steve at holdenweb.com>:
>> 
>>>Pierre Quentel wrote:
>>>
>>>>Hi all,
>>>>
>>>>In some program I was testing if a variable was a boolean, with this 
>>>>test : if v in [True,False]
>>>>
>>>>My script didn't work in some cases and I eventually found that for v = 
>>>>0 the test returned True
>>>>
>>>>So I changed my test for the obvious "if type(v) is bool", but I still 
>>>>find it confusing that "0 in [True,False]" returns True
>>>>
>>>>By the way, I searched in the documentation what "obj in list" meant and 
>>>>couldn't find a precise definition (does it test for equality or 
>>>>identity with one of the values in list ? equality, it seems) ; did I 
>>>>miss something ?
>>>>
>>>
>>>It actually uses the __contains__() method of the right-hand operand, 
>>>and in the case of a list that will test for equality of the left-hand 
>>>operand to one of the list elements. Since False == 0 that's why you see 
>>>what you do.
>>>
>>>The really interesting question your post raises, though, is "Why do you 
>>>feel it's necessary to test to see whether a variable is a Boolean?".
>> 
>> 
>> I can give you one example. I have written a tube class. A tube behaves
>> like Queue but it has additional code so that it can be registed with
>> gtk in the same way as file descriptor can be registered with
>> io_add_watch. The way this is implemented is by registering an idle
>> handler when the tube is not empty and removing it when the tube is
>> empty. So I have a variable cb_src (for callback source) that can be
>> a boolean or an integer. The possible values are
>> 
>>   False: Not registered by the user
>>   True: Registered by the user but no nternal idle callback registerd
>>   a number: gtk integer ID, from the registered idle callback handler.
>> 
> Well I guess you'd better hope that gtk never returns a zero or one, then.

Why? It won't break my code.

> Note, though, that True and False are defined to be singleton instances, 
> so it *is* permissible to say
>
>      if i is False:
>
> >>> 0 is False
> False
> >>> 1 is True
> False
> >>>
>
> However I must say the coupling in that interface has a very definite 
> code smell. Why not use two variables, a Boolean "registered" and an 
> integer ID that is meaningless when registered is False?

Because the integer ID can be meaningless when registered is True.
If I should use two variables, the "registered" variable should
be a three value variable. Something like:

  0: Not registered by the user
  1: Registered by the user but no internal idle callback registerd
  2: internal idle callback registerd

Only in the last case is the integer ID meaningfull. But IMO I buy
nothing buy seperating the information over two variables. Checking
whether the "registered" variable is 2 or not, doesn't buy me
anything over checking whether the cb_src is of BooleanType or
not.

And having the information in one variable means I have to worry
less about synchronisation. If I register the internal idle
handler I just store its ID in cb_src, without having to worry
about another variable that has to be set right.

-- 
Antoon Pardon



More information about the Python-list mailing list