213 lines
7.3 KiB
Plaintext
213 lines
7.3 KiB
Plaintext
PEP: 285
|
||
Title: Adding a bool type
|
||
Version: $Revision$
|
||
Last-Modified: $Date$
|
||
Author: guido@python.org (Guido van Rossum)
|
||
Status: Draft
|
||
Type: Standards Track
|
||
Created: 8-Mar-2002
|
||
Python-Version: 2.3
|
||
Post-History: 8-Mar-2002
|
||
|
||
|
||
Abstract
|
||
|
||
This PEP proposes the introduction of a new built-in type, bool,
|
||
with two constants, False and True. The bool type would be a
|
||
straightforward subtype (in C) of the int type, and the values
|
||
False and True would behave like 0 and 1 in most respects (for
|
||
example, False==0 and True==1 would be true) except repr() and
|
||
str(). All built-in operations that conceptually return a Boolean
|
||
result will be changed to return False or True instead of 0 or 1;
|
||
for example, comparisons and the "not" operator.
|
||
|
||
|
||
Rationale
|
||
|
||
Most languages eventually grow a Boolean type; even C99 has one.
|
||
|
||
Many programmers apparently feel the need for a Boolean type; most
|
||
Python documentation contains a bit of an apology for the absence
|
||
of a Boolean type. I've seen lots of module that defined
|
||
constants "False=0" and "True=1" (or similar) at the top and used
|
||
those. The problem with this is that everybody does it
|
||
differently. For example, should you use "FALSE", "false",
|
||
"False", "F" or even "f"? And should false be the value zero or
|
||
None, or perhaps a truth value of a different type that will print
|
||
as "true" or "false"? Adding a standard bool type to the language
|
||
resolves those issues.
|
||
|
||
Some external libraries (like databases and RPC packages) need to
|
||
be able to distinguish between Boolean and integral values, and
|
||
while it's usually possible to create a solution, it would be
|
||
easier if the language offered a standard Boolean type.
|
||
|
||
And here's an argument derived from teaching Python. When showing
|
||
people comparison operators etc. in the interactive shell, I think
|
||
this is a bit ugly:
|
||
|
||
>>> a = 13
|
||
>>> b = 12
|
||
>>> a > b
|
||
1
|
||
>>>
|
||
|
||
If this was:
|
||
|
||
>>> a > b
|
||
True
|
||
>>>
|
||
|
||
it would require one millisecond less thinking each time a 0 or 1
|
||
was printed.
|
||
|
||
There's also the issue (which I've seen puzzling even experienced
|
||
Pythonistas who had been away from the language for a while) that if
|
||
you see:
|
||
|
||
>>> cmp(a, b)
|
||
1
|
||
>>> cmp(a, a)
|
||
0
|
||
>>>
|
||
|
||
you might be tempted to believe that cmp() also returned a truth
|
||
value. If ints are not (normally) used for Booleans results, this
|
||
would stand out much more clearly as something completely different.
|
||
|
||
|
||
Specification
|
||
|
||
The following Python code specifies most of the properties of the
|
||
new type:
|
||
|
||
class bool(int):
|
||
|
||
def __new__(cls, val=0):
|
||
# This constructor doesn't return a new instance;
|
||
# it returns an existing instance
|
||
if val:
|
||
return True
|
||
else:
|
||
return False
|
||
|
||
def __repr__(self):
|
||
if self:
|
||
return "True"
|
||
else:
|
||
return "False"
|
||
|
||
__str__ = __repr__
|
||
|
||
def __and__(self, other):
|
||
if isinstance(other, bool):
|
||
return bool(int(self) & int(other))
|
||
else:
|
||
return int.__and__(self, other)
|
||
|
||
__rand__ = __and__
|
||
|
||
def __or__(self, other):
|
||
if isinstance(other, bool):
|
||
return bool(int(self) | int(other))
|
||
else:
|
||
return int.__or__(self, other)
|
||
|
||
__ror__ = __or__
|
||
|
||
def __xor__(self, other):
|
||
if isinstance(other, bool):
|
||
return bool(int(self) ^ int(other))
|
||
else:
|
||
return int.__xor__(self, other)
|
||
|
||
__rxor__ = __xor__
|
||
|
||
# Bootstrap truth values through sheer willpower
|
||
False = int.__new__(bool, 0)
|
||
True = int.__new__(bool, 1)
|
||
|
||
The values False and True will be singletons, like None; the C
|
||
implementation will not allow other instances of bool to be
|
||
created. At the C level, the existing globals Py_False and
|
||
Py_True will be identical to the built-in singletons False and
|
||
True.
|
||
|
||
All built-in operations that are defined to return a Boolean
|
||
result will be changed to return False or True instead of 0 or 1.
|
||
In particular, this affects comparisons (<, <=, ==, !=, >, >=, is,
|
||
is not, in, not it), the unary operator 'not', the built-in
|
||
functions callable(), hasattr(), isinstance() and issubclass(),
|
||
the dict method has_key(), the string and unicode methods
|
||
endswith(), isalnum(), isalpha(), isdigit(), islower(), isspace(),
|
||
istitle(), isupper(), and startswith(), the unicode methods
|
||
isdecimal() and isnumeric(), and the closed attribute of file
|
||
objects.
|
||
|
||
Note that subclassing from int means that True+1 is valid and
|
||
equals 2, and so on. This is important for backwards
|
||
compatibility: because comparisons and so on currently return
|
||
integer values, there's no way of telling what uses existing
|
||
applications make of these values.
|
||
|
||
|
||
Compatibility
|
||
|
||
Because of backwards compatibility, the bool type lacks many
|
||
properties that some would like to see. For example, arithmetic
|
||
operations with one or two bool arguments is allowed, treating
|
||
False as 0 and True as 1. Also, a bool may be used as a sequence
|
||
index.
|
||
|
||
I don't see this as a problem, and I don't want evolve the
|
||
language in this direction either; I don't believe that a stricter
|
||
interpretation of "Booleanness" makes the language much clearer.
|
||
|
||
Another consequence of the compatibility requirement is that the
|
||
expression "True and 6" has the value 6, and similarly the
|
||
expression "False or 0" has the value 0. The "and" and "or"
|
||
operators are usefully defined to return the first argument that
|
||
determines the outcome. Of course, if both arguments are bools,
|
||
the outcome is always a bool. It can also easily be coerced into
|
||
being a bool by writing for example "bool(x and y)".
|
||
|
||
|
||
Issues
|
||
|
||
Because the repr() or str() of a bool value is different from an
|
||
int value, some code (for example doctest-based unit tests, and
|
||
possibly database code that relies on things like "%s" % truth)
|
||
may fail. How much of a backwards compatibility problem this will
|
||
be, I don't know. If we this turns out to be a real problem, we
|
||
could changes the rules so that str() of a bool returns "0" or
|
||
"1", while repr() of a bool still returns "False" or "True".
|
||
|
||
Other languages (C99, C++, Java) name the constants "false" and
|
||
"true", in all lowercase. In Python, I prefer to stick with the
|
||
example set by the existing built-in constants, which all use
|
||
CapitalizedWords: None, Ellipsis, NotImplemented (as well as all
|
||
built-in exceptions). Python's built-in module uses all lowercase
|
||
for functions and types only. But I'm willing to consider the
|
||
lowercase alternatives if enough people think it looks better.
|
||
|
||
|
||
Implementation
|
||
|
||
An experimental, but fairly complete implementation in C has been
|
||
uploaded to the SourceForge patch manager:
|
||
|
||
http://sourceforge.net/tracker/index.php?func=detail&aid=528022&group_id=5470&atid=305470
|
||
|
||
|
||
Copyright
|
||
|
||
This document has been placed in the public domain.
|
||
|
||
|
||
|
||
Local Variables:
|
||
mode: indented-text
|
||
indent-tabs-mode: nil
|
||
fill-column: 70
|
||
End:
|