Basically W, X, Y and Z are propositions
that are either true or false, and the puzzle lists a few statements
such as "Exactly one of X, Y and Z is true", and I'm trying to work out
a little algorithm that might test for this kind of stuff.
Okay. You don't need to worry about the "is" tests at all.
Python always represents the value "True" with a reference to a True
object, and likewise "False" is a reference to a False object. To save
memory, Python has just one of each object, so:
a = False
b = False
a is b # this will always be true
As some other posters showed by example, but didn't really explain, Python
will *sometimes* but not always reuse integer objects. For common integer
values such as 0 and 1, Python will reuse the objects; for uncommon
(larger) values, Python usually won't. So:
a = 12345
b = 12345
a is b # probably not true
a = 0
b = 0
a is b # always true
A key point is that you never really "assign a value to a variable". What
you really do is "bind an object reference to a name". The long,
simultaneous assignment form binds the same object reference to multiple
variables:
a = b = c = d = 12345
a is b # always true
But as soon as you reassign any of the variables you will rebind the name
to some other object reference:
a += 1
a is b # definitely false
a = 12345
a is b # probably false
Python *could* notice that it already has an integer object with the value
12345, and rebind the name a with a reference to it. But in practice
Python will probably just create a new integer object with value 12345,
since the Python interpreter doesn't spend large amounts of time looking
through its collection of objects to find ones that can be reused.
Python also has exactly one "None" object, and always uses references to
it whenever you reference None in your code. This is why it is preferred
Python style to test for None with an "is" test:
a is None
Anyway, the major point I want you to take away from all this: it doesn't
matter whether the "is" test succeeds or fails, if all you care about is
the *value* of a variable. Python reuses object references to save
memory, because this doesn't affect expressions that only care about the
*value*. Your logic tests only care about True vs. False; they don't care
about the underlying implementation of how True and False are expressed.
Another thing I'm trying to do is write a function that tests to see if
a list contains exactly one true item, and the rest are false (obviously
this would have to be a list of boolean values, I guess). I'm sure this
isn't a handy utility, but I enjoy figuring out how to implement it.
This is a simple problem. I suggest you loop over the list and simply
count how many values are false, and how many are true. I just wrote and
tested this function in about a minute.
The list doesn't have to be a list of booleans, actually. Python has a
set of rules for evaluating other values as booleans:
if 0:
pass # never executed; 0 always false
if "":
pass # never executed; 0-length string always false
if []:
pass # never executed; 0-length list always false
So, don't test to see if something is equal to True or False:
if 0 == False:
pass # never executed; False and 0 do not directly compare
You *could* do this, but I don't really recommend it:
if bool(0) == False:
pass # always executed
Do this:
if not 0:
pass # always executed
if 1:
pass # always executed
To convert a random value into a boolean value, you could use either
"bool()" or you could use "not not":
a = not not 0
b = bool(0)
"not not" will work on older versions of Python that didn't have an
explicit boolean type; "not 0" would return 1 in that case. "bool()"
will work in Python 2.2 and newer.