# Numbers and truth values

Discussion in 'Python' started by Szabolcs, Apr 28, 2007.

1. ### SzabolcsGuest

Newbie question:

Why is 1 == True and 2 == True (even though 1 != 2),
but 'x' != True (even though if 'x': works)?

Szabolcs, Apr 28, 2007

2. ### Michael HoffmanGuest

Szabolcs wrote:

> Why is 1 == True and 2 == True (even though 1 != 2),

Not what I get.

Python 2.5 (r25:51908, Mar 13 2007, 08:13:14)
[GCC 3.4.4 (cygming special, gdc 0.12, using dmd 0.125)] on cygwin
>>> 2 == True

False
--
Michael Hoffman

Michael Hoffman, Apr 28, 2007

3. ### Irmen de JongGuest

Szabolcs wrote:
> Newbie question:
>
> Why is 1 == True and 2 == True (even though 1 != 2),
> but 'x' != True (even though if 'x': works)?

[E:\Projects]python
Python 2.5.1 (r251:54863, Apr 18 2007, 08:51:08) [MSC v.1310 32 bit (Intel)] on win32
>>> 2==True

False
>>>

Anyway,
it helps to think about value domains (in your examples, numbers and strings)
as having a single "null" value, and non-null values.
The null value is considered False.
The non-null values are considered True.

The null value for numbers is 0 obviously, and for strings it is ''
(the empty string).
Non-zero numbers and non-empty strings are considered "True" when used
in a boolean expression.

--Irmen

Irmen de Jong, Apr 28, 2007
4. ### Steven D'ApranoGuest

On Sat, 28 Apr 2007 14:33:23 +0200, Szabolcs wrote:

> Newbie question:
>
> Why is 1 == True and 2 == True (even though 1 != 2),
> but 'x' != True (even though if 'x': works)?

Everything in Python has a truth-value. So you can always do this:

if some_object:
print "if clause is true"
else:
print "else clause"

no matter what some_object is.

The constants True and False are a pair of values of a special type bool.
The bool type is in fact a sub-class of int:

>>> issubclass(bool, int)

True
>>> 7 + False

7
>>> 7 + True

8

Can you guess what values True and False are "under the hood"?

>>> 1 == True

True
>>> 0 == False

True
>>> 2 == True

False
>>> if 2:

.... print "2 is considered true"
....
2 is considered true

If you are getting different results, the chances are that you have
accidentally reassigned that names True or False:

>>> True = 2 # DON'T DO THIS!!!
>>> 2 == True

True

--
Steven.

Steven D'Aprano, Apr 28, 2007
5. ### SzabolcsGuest

Steven D'Aprano wrote:
>
>>>> 1 == True

> True
>>>> 0 == False

> True
>>>> 2 == True

> False

Oh my goodness! Now I also get 2 != True. I really don't know what
happened. Most probably this (as a result of mistyping):

>
>>>> True = 2 # DON'T DO THIS!!!
>>>> 2 == True

> True
>

But shouldn't Python forbid this? Is it possible to get a warning when
unintentionally redefining built-in thing?

Szabolcs, Apr 28, 2007
6. ### Steven D'ApranoGuest

On Sat, 28 Apr 2007 15:36:19 +0200, Szabolcs wrote:

>>>>> True = 2 # DON'T DO THIS!!!
>>>>> 2 == True

>> True
>>

>
> But shouldn't Python forbid this? Is it possible to get a warning when
> unintentionally redefining built-in thing?

Python forbids very few things in comparison to other languages. The
attitude is "We're all adults here". Because Python is such a dynamic
language, it is often hard for the compiler to tell the difference between
something you are doing deliberately and a mistake.

--
Steven.

Steven D'Aprano, Apr 28, 2007
7. ### Alex MartelliGuest

Szabolcs <> wrote:
...
> >>>> True = 2 # DON'T DO THIS!!!
> >>>> 2 == True

> > True

>
> But shouldn't Python forbid this? Is it possible to get a warning when
> unintentionally redefining built-in thing?

Python can be changed to make some non-reserved builtin identifiers into
reserved words, going through a stage where this is allowed but gives a
warning. This happened in recent years for assignments to None, which
were legal back in 2.2 and earlier:

\$ python2.3 -c'None=23'
<string>:1: SyntaxWarning: assignment to None
\$ python2.4 -c'None=23'
File "<string>", line 1
SyntaxError: assignment to None

....and, as you can see, gave syntax warnings in 2.3, becoming syntax
errors in 2.4 and later versions.

However, Python has a somewhat large and growing number of builtin
identifiers:

\$ python2.3 -c'print len(__builtins__.__dict__)'
124
\$ python2.4 -c'print len(__builtins__.__dict__)'
128
\$ python2.5 -c'print len(__builtins__.__dict__)'
133

while keywords (reserved words) are far fewer, and more constrained in
their growth:

\$ python2.3 -c'import keyword; print len(keyword.kwlist)'
29
\$ python2.4 -c'import keyword; print len(keyword.kwlist)'
29
\$ python2.5 -c'import keyword; print len(keyword.kwlist)'
31

so, making all builtins into keywords is unlikely to happen: it would
break a lot of existing code in exchange for a minor benefit.

It _would_ surely be possible to make Python behave this way only when a
certain commandline flag or environment variable is present, e.g. by
tweaking the implementation of the relevant bytecodes:

>>> def f():

.... global aglobal
.... aglobal = 23
.... alocal = 45
....
>>> dis.dis(f)

3 STORE_GLOBAL 0 (aglobal)

9 STORE_FAST 0 (alocal)
15 RETURN_VALUE

STORE_GLOBAL and STORE_FAST. However, this might slow down normal
operation (by needing to check some flag at each STORE_...).

Perhaps a better approach is to perform your checking with a tool that
is _separate_ from "Python proper". Wouldn't it be great to have a tool
to check Python sources, one which we could name, for example,
pychecker, that we could run as follows...:

\$ cat >ba.py
False = 23

\$ pychecker ba.py
Processing ba...

Warnings...

ba.py:1: Should not assign to False, it is (or will be) a builtin

Rejoyce! <http://pychecker.sourceforge.net/> ...

There are other tools to perform such checks, such as pylint,
<http://www.logilab.org/857>, which is quite a bit more complicated but
can perform many more checks (and can be integrated into PyDev, an
Eclipse add-on which some people like to use as a Python IDE), and, I
believe, a few other with slightly different slants (such as pyflakes,
<http://www.divmod.org/projects/pyflakes>, which does fewer checks but
does them faster and in a way that's safe against potentially-evil
code).

By the way, both of these tools (and many other tools, and a lot of
other useful tips) are mentioned at
<http://www.python.org/doc/faq/programming/> , the Python Programming
FAQ (it's a bit dated, but if you find any problem with it, just like
with any other piece of official Python docs, bugs and suggested patches
are welcome at the usual location,
<http://sourceforge.net/projects/python> ).

Perhaps one day some variant of pychecker and/or pylint can be
integrated in Python itself, and executed (for example at each import)
if that's indicated by some appropriate flag or environment variable;
however, for us command-line dinosaurs, the people who prefer running
python at a shell prompt (rather than more advanced things such as
ipython, or IDEs such as PyDev, IDLE, etc, etc) this doesn't really tend
to be that high a priority, as we're quite used to "not necessarily
auto-integrated" tools; it's probably a higher priority to get pychecker
or something like that integrated with other IDEs such as IDLE (I don't
know, besides PyDev's ability to use pylint, which other such
integrations currently exist -- anybody?).

Alex

Alex Martelli, Apr 28, 2007
8. ### John NagleGuest

Steven D'Aprano wrote:
> On Sat, 28 Apr 2007 15:36:19 +0200, Szabolcs wrote:
>
>
>>>>>>True = 2 # DON'T DO THIS!!!
>>>>>>2 == True
>>>
>>>True
>>>

>>
>>But shouldn't Python forbid this? Is it possible to get a warning when
>>unintentionally redefining built-in thing?

>
>
> Python forbids very few things in comparison to other languages. The
> attitude is "We're all adults here". Because Python is such a dynamic
> language, it is often hard for the compiler to tell the difference between
> something you are doing deliberately and a mistake.

I'd have to consider that a bug.

Some very early FORTRAN compilers allowed you to redefine
integer constants:

CALL SET(25,99)
WRITE (6,100) 25
100 FORMAT(I6)

SUBROUTINE SET(IVAR, INEWVAL)
IVAR = INEWVAL

would print

99

It was generally agreed by 1970 or so that this was a bad idea,
and was taken out of the language.

C originally didn't have a Boolean type, and it took years to
get that in and uniformly defined. But in the end, "true" and
"false" were reserved words.

"True", "False", and "None" should be reserved words in Python.

John Nagle

John Nagle, Apr 28, 2007
9. ### Alex MartelliGuest

John Nagle <> wrote:
...
> I'd have to consider that a bug.
>
> Some very early FORTRAN compilers allowed you to redefine
> integer constants:
>
>
> CALL SET(25,99)
> WRITE (6,100) 25
> 100 FORMAT(I6)
>
> SUBROUTINE SET(IVAR, INEWVAL)
> IVAR = INEWVAL
>
> would print
>
> 99
>
> It was generally agreed by 1970 or so that this was a bad idea,
> and was taken out of the language.

It was still perfectly legal in the Fortran 1977 standard for a compiler
to cause this effect, because the Fortran source you quote has
*undefined behavior* -- the compiler doesn't have to diagnose this error
and can cause any effects as a consequence.

The point of Fortran is to let the compiler generate the fastest code it
can, NOT to "tenderly hold your hand" lest scary bugs disturb your
blessed and dreamy innocence.

If this has changed in the Fortran 1990 standard or later, then I can
only say I'm happy I stopped using Fortran heavily before such standards
became widespread in commonly available compilers -- by the late '90s,
when I was still using _some_ Fortran, it was Fortran '77, as that was
the version that was widely available and well optimized.

Python is not particularly focused on coddling the programmer lest he or
she (horrors!) make a mistake, either; rather, it embodies well 4 of the
5 principles that make up the "Spirit of C" according to the Preface to
C's ISO Standard -- "trust the programmer", "don't stop the programmer
from doing what needs to be done", "keep the language small and simple"
(the 4th one, "offer only one way to perform an operation", is not
germane here). Making the language more complicated (e.g., with more
reserved words) because you _don't_ trust the programmer and badly wants
to stop him/her from doing something is not well consistent with these
principles. Maybe somebody assigning a value to True or False is a
common error, but much of my livelihood over the last 10 years has been
about mentoring/coaching programmers in Python, and that's one error I
have *NEVER* observed, so I'd need a lot of empirical evidence to
convince me it's worth adding two more reserved words to Python's
reasonably short list (I feel much the same way about None, by the way).
pychecker, pylint, and friends, are a much better way to detect and warn
about all sort of anomalies of this kind.

Alex

Alex Martelli, Apr 28, 2007
10. ### SzabolcsGuest

Alex Martelli wrote:
> Maybe somebody assigning a value to True or False is a
> common error, but much of my livelihood over the last 10 years has been
> about mentoring/coaching programmers in Python, and that's one error I
> have *NEVER* observed, so I'd need a lot of empirical evidence to
> convince me it's worth adding two more reserved words to Python's
> reasonably short list (I feel much the same way about None, by the way).
> pychecker, pylint, and friends, are a much better way to detect and warn
> about all sort of anomalies of this kind.

Yes, I admit that it was a very stupid mistake. (Though I'm not even
sure that this is what happened. Next time I should probably sleep on
it, and try it again the next day, to avoid posting such a stupid
question again.) But note that I was using Python interactively (just
experimenting with it). It is very unlikely that someone would write
things like True == 2 without any additional context in a real program.
(Actually it is unlikely that someone would write this in any
circumstance in a real program.)

But I still think that it is an inconsistency to allow to redefine a
_value_ like True or False (not a built-in function that may have been
missing in earlier versions). Saying True = 2 is just like saying 3 = 2.

Learning about pylint was very useful (thanks for the advice!) -- it
helps in catching those kinds of errors that surface only at runtime in
Python programs, but are easily caught at compile time in compiled
languages.

Szabolcs, Apr 28, 2007
11. ### Mel WilsonGuest

John Nagle wrote:
> "True", "False", and "None" should be reserved words in Python.

The permissiveness makes it less painful to upgrade to new versions of
Python. True and False only recently got assigned conventional
values, but you can still import old modules without worrying whether
they might violate the new rule; if True and False once meant
something special to them, it will still mean the same thing.

Meanwhile new code can follow the new conventions.

Mel.

Mel Wilson, Apr 29, 2007
12. ### Steven D'ApranoGuest

On Sat, 28 Apr 2007 11:35:36 -0700, John Nagle wrote:

>> Python forbids very few things in comparison to other languages. The
>> attitude is "We're all adults here". Because Python is such a dynamic
>> language, it is often hard for the compiler to tell the difference between
>> something you are doing deliberately and a mistake.

>
> I'd have to consider that a bug.

[snip]

> "True", "False", and "None" should be reserved words in Python.

What are you going to do about the code that pre-dates the introduction of
bools that defines

False = 0
True = not False

at the start of the module? The Python philosophy is to break existing
code as little as possible (at least until Python 3).

--
Steven

Steven D'Aprano, Apr 29, 2007
13. ### Steven D'ApranoGuest

On Sat, 28 Apr 2007 23:54:01 +0200, Szabolcs wrote:

> But I still think that it is an inconsistency to allow to redefine a
> _value_ like True or False (not a built-in function that may have been
> missing in earlier versions). Saying True = 2 is just like saying 3 = 2.

Well, it might seem that way, but it isn't really. It's more like having
built-in names

One = 1
Zero = 0

(plus some special code so that when you say "print One" it prints
"One" rather than 1) in Python. You wouldn't be surprised to be able to
redefine One = 2 there, would you?

The ability to shadow built-ins is a fact of life in the Python world.
Python has a lot of built-ins, and very few keywords, and that situation
is unlikely to change. As Alex explained, the philosophy is not to slow
the compiler and interpreter down with checks against those sort of
problems directly, but to trust the programmer to call external tools like
pylint and pychecker if they want. It may be that True and False will
(like None before it) be moved from the built-ins category into the
keyword category, but I don't think that's the most pressing problem in
Python.

--
Steven.

Steven D'Aprano, Apr 29, 2007
14. ### Alex MartelliGuest

Szabolcs <> wrote:

> But I still think that it is an inconsistency to allow to redefine a
> _value_ like True or False (not a built-in function that may have been
> missing in earlier versions). Saying True = 2 is just like saying 3 = 2.

True and False were *ALSO* missing in earlier versions of Python (2.2.1
and back -- they were introduced in 2.2.2, smack in the middle of a
minor release cycle, a release engineering error which Guido has vowed
never to repeat).

There's a lot of code around that starts with

False = 0
True = not False

(or similar), so it can run just as well on (e.g) 2.2.1 (and earlier) as
2.2.2 (and later) -- breaking all of that code which always worked fine
is a decision not to be taken as lightly as you appear to imply.

Alex

Alex Martelli, Apr 29, 2007
15. ### BeliavskyGuest

On Apr 28, 4:05 pm, (Alex Martelli) wrote:
> John Nagle <> wrote:
>
> > I'd have to consider that a bug.

>
> > Some very early FORTRAN compilers allowed you to redefine
> > integer constants:

>
> > CALL SET(25,99)
> > WRITE (6,100) 25
> > 100 FORMAT(I6)

>
> > SUBROUTINE SET(IVAR, INEWVAL)
> > IVAR = INEWVAL

>
> > would print

>
> > 99

>
> > It was generally agreed by 1970 or so that this was a bad idea,
> > and was taken out of the language.

>
> It was still perfectly legal in the Fortran 1977 standard for a compiler
> to cause this effect, because the Fortran source you quote has
> *undefined behavior* -- the compiler doesn't have to diagnose this error
> and can cause any effects as a consequence.
>
> The point of Fortran is to let the compiler generate the fastest code it
> can, NOT to "tenderly hold your hand" lest scary bugs disturb your
> blessed and dreamy innocence.

The point of Fortran has been to make scientific programmers more
productive, and catching errors and producing fast programs are BOTH
ways of doing that. Compilers are judged on BOTH criteria:
speed: http://www.polyhedron.com/pb05/linux/f90bench_p4.html
diagnostics: http://www.polyhedron.com/pb05/linux/diagnose.html

If there is a compiler with great compile- and run-time debugging
capability with the right options turned on, and if the compiler also
produces optimally fast code with another set of options (or if
another compiler does this), isn't that the best of both worlds?

> If this has changed in the Fortran 1990 standard or later, then I can
> only say I'm happy I stopped using Fortran heavily before such standards
> became widespread in commonly available compilers -- by the late '90s,
> when I was still using _some_Fortran, it was Fortran '77, as that was
> the version that was widely available and well optimized.

I don't think the official status of such has changed -- it's still
illegal to change a constant and the compiler is still not required to
catch the error -- but compilers may be more likely to reject
such code as before, helping programmers spot errors. IMO that's a
good thing.

When is no longer using a language, one has the luxury of thinking
about it in an ideological rather than practical manner.

Beliavsky, Apr 29, 2007
16. ### Alex MartelliGuest

Beliavsky <> wrote:
...
> > If this has changed in the Fortran 1990 standard or later, then I can
> > only say I'm happy I stopped using Fortran heavily before such standards
> > became widespread in commonly available compilers -- by the late '90s,
> > when I was still using _some_Fortran, it was Fortran '77, as that was
> > the version that was widely available and well optimized.

>
> I don't think the official status of such has changed -- it's still
> illegal to change a constant and the compiler is still not required to
> catch the error

Oh good -- I'm happy to hear that the original spirit IS still around.

> -- but compilers may be more likely to reject
> such code as before, helping programmers spot errors. IMO that's a
> good thing.

In general, as an engineer, I think that making tools more complicated
so that a single tool can serve multiple purposes is not necessarily a
win. I do not want one pair of shoes that are designed to be excellent
for running AND for dancing AND for mountain hiking: I'd much rather
have three specialized pairs of shoes instead, one pair for running, one
for dancing, one for hiking.

Similarly, I'd rather have one tool to take presumably-correct sources
and generate great machine code from them, and separate tools to nitpick
the bejeezus out of the sources to make really sure they ARE indeed
perfectly correct from all viewpoints. Two (or more) simple, fully
specialized tools make for a better toolbox than one complex,
multi-purpose one. Few except engineers seem to understand this.

> When is no longer using a language, one has the luxury of thinking
> about it in an ideological rather than practical manner.

I thought about Fortran in exactly the same way when I was doing most of
my coding in it, and also using it to teach "numerical computing" in
university. Most errors came (and still come) from people who just
don't understand the underlying mathematical nature and realities of
floating point (and numerical computations more generally), and I never
expected a compiler to magically start warning the user about "you're
using a very badly conditioned algorithm for this computation", the
one thing that would have really saved me a lot of time in my advisory
and teaching roles. Exactly the same problems keep surfacing in
programs in Python and any other language too, barely veiled by today's
growing propensity for double-precision and wider-yet floats; offering a
rich library of functions is NOT a viable replacement for understanding
and approaching computation correctly (users will just call extremely
general library functions, rather than understand their problem's
specific "geometries" and address them appropriately).

(Let me offer one more plug for my favorite "book about programming
without a single line of code in it", Foreman Acton's "Real computing
made real", now out in a wonderfully cheap Dover edition: Acton makes
this case better than I've ever seen it made elsewhere, and offers many
excellent examples of how numerical computation SHOULD be done).

Alex

Alex Martelli, Apr 30, 2007