Velocity Reviews > Numbers and truth values

# Numbers and truth values

Szabolcs
Guest
Posts: n/a

 04-28-2007
Newbie question:

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

Michael Hoffman
Guest
Posts: n/a

 04-28-2007
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

Irmen de Jong
Guest
Posts: n/a

 04-28-2007
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:0 [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

Steven D'Aprano
Guest
Posts: n/a

 04-28-2007
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.

Szabolcs
Guest
Posts: n/a

 04-28-2007
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?

Steven D'Aprano
Guest
Posts: n/a

 04-28-2007
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.

Alex Martelli
Guest
Posts: n/a

 04-28-2007
Szabolcs <(E-Mail Removed)> 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

John Nagle
Guest
Posts: n/a

 04-28-2007
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

Alex Martelli
Guest
Posts: n/a

 04-28-2007
John Nagle <(E-Mail Removed)> 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

Szabolcs
Guest
Posts: n/a

 04-28-2007
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.