There is no such things as a "principle of least surprise" or if you insist
there is, I can nominate many more such "rules" such as "the principle of
get out of my way and let me do what I want!"
Computer languages with too many rules are sometimes next to unusable in
I am neither defending or attacking choices Python or other languages have
made. I merely observe and agree to use languages carefully and as
But consider that the history of computer science when it came to counting
numbers depends on bits. Pretty much everything is in base two. When space
was a major concern, or efficiency, people often used smaller units when
possible. If you look at something like how one stored files on UNIX, they
set aside a group of bits of some size as part of some larger entity and
each bit represented a BOOLEAN concept of 1 and 0 to mean is that bit set to
some sort of ON or off. Three of those bits controlled whether the owner of
a file had permission to read, write or execute the file. Another three
governed the same idea for everyone listed as being in the same group and
another three listed permissions for "other". The whole thing took up more
room in something larger where perhaps 14 bytes (of 8 bits each) were set
aside to hold a filename and other parts held things like perhaps a link
count. At some point they noticed the chink had a few unused bits and
invented a purpose for them and patented the setuid bit concept and the
So back to integers. You can use 16 bits in a signed or unsigned manner and
cover numbers between a low and a high. You can use 64 bits or 128 bits or
whatever makes you happy and it remains an integer albeit trying to do
arithmetic between them can result in an overflow situation and the hardware
often does not trivially support it. It turned out that often there was a
use for 8 bits even though they hold only 256 possible integers and before
the alphabets grew to need more room, that was enough space for an ASCII or
EBCDIC character. Sometimes you did things at the nibble level of 4 bits or
a hex digit. Booleans were even simpler at 1 bit. But all SIZES can be used
to hold some range of integers. Modern python has made some extensions that
let you store integers of unlimited size but underneath it all, the
operations are still dealing with the same ideas as shorter versions
including ones that hold more limited numbers down to binary/Boolean.
So if you want to save space in memory or on a hard disk or sending across
the internet, you well may want the ability to set aside a "char" to hold
smallish numbers or treat a Boolean value as a "1" and so on. If you know
what you are doing, it is not much of a surprise. On many systems, there may
well be some registers that load 32 or 64 bits and then you use them for
something like addition. If I supply a 16-bit or 8-bit or even 1-bit
quantity, the software generally ends up putting it into the standard size
register and pads unused areas with zeroes. No big deal. If the number is
too large to fit, as with any larger integer in python, then the software
does whatever it needs to such as calculating how many chunks need adding
and doing the addition in the same registers in smaller chunks while
managing any carryover and finally assembling the possibly longer result.
Floating point is a slightly different animal than the others that arguably
are all of a similar if not identical type. But even there, your storage has
two components which are actually both seen as integers of sorts. 6.02 times
ten to the 23rd might also be written as 602 times ten to the 21st and now
you have two integers you can use in calculations that registers do on
integers and recombine into a new floating point format. Or, of course, you
might have hardware that does the work.
If you move on to complex variables, they tend to be a sort of named tuple
containing a real and imaginary part with special rules on how to add and do
other mathematical operations. Underneath it all, they are often implemented
as a pair of linked floating point structures. And in one sense, all real
numbers represented in a floating point variable are a strict subset of
complex numbers with imaginary part being zero. All integers are in a sense
floating point numbers with fractional part (meaning beyond the decimal
point) being all zeroes. Similarly, all smaller integral types such as
bytes are Booleans are a limited subset.
So some of us who know a bit about CS and not just this language, are less
often surprised by a choice of implementations. We often do not mix things
but when we do, we know what we are doing much of the time and appreciate
how easily it can be done. Consider what happens if you want to circularly
permute alphabetic characters of the English Alphabet by 13, sometimes
called rot13. There are quite a few ways to do it but one of them depends on
the fact that the numerical value in ASCII of the letter 'A' is one less
than of the next letter, 'B' and so on to 'Z'. They are contiguous but note
upper and lower cases letters are not back to back. So a piece of code that
says that if a character is between the numerical representation of 'A' and
halfway to the end, then add 13, and if it is higher, then add 13 and
subtract 26 (or obviously just subtract 13) to slide it circularly back, is
a valid way to do the permutation. But it involves adding what may seem to
be a 32-bit integer containing a number like 13 or 26 to an 8-bit character
resulting in an 8-bit character. Should that be illegal?
Well, in a sense it is illegal and you should be forced to create something
of type char that holds whatever 13 is, which probably is a
control-character and then either use operations that add or subtract 8-bit
items, OR you may widen the character to 32 bits and do the math with a
32-bit representation of 13/26 then narrow the result back into eight bits.
But lots of systems know how to automate this for you or even do it more
efficiently than you might have done on your own and do it differently on
different computer architectures. One goal of programming is to make life as
easy as possible for a programmer to be productive or make fewer errors and
so on. Sometimes not being surprised is a valid goal. But a language like
Python may not lean the way you think.
I once bashed my head at languages like PASCAL and even C as it often took
some work to do things like process a list of heterogenous contents
including perhaps some I may have no idea about at compile time. You
sometimes needed to convince the compiler to loosen up on rules such as by
declaring a union of several types. Python often does not care what anything
is and just passes it on. You, as the writer of a function may have to check
things like whether what you were passed is hashable or is of a numeric
type. You may simply take any argument(s) and coerce them into a new list
object to guarantee that whatever it is can now handle what lists supply.
This means you are often free to use the function with arguments that are
tuples or iterators and not just lists. Yes, someone using the function may
yet surprise you and you may want to write defensive code that checks
up-front and stops if called in an unexpected way. But you can write the
main function fairly quickly while assuming no surprises and bullet-proof it
later once it seems to work for what you want. The alternative is to keep
fighting with a compiler (or a static checker like mpy) before anything gets
The surprise there is when they fire you from your job for not seeming to do
much for many months.
Having said that, I have had many surprises in many languages such as some
that help you so much that they handle 3 + "two" for you and return 5 or
maybe "five" rather than suggest you may have name an error and meant 3 +
int(english_number_to_string("two")) or perhaps "3" + "two" ...
I am surprised how this message got this long! Aaargh!
From: Python-list <firstname.lastname@example.org> On
Behalf Of Dino
Sent: Wednesday, January 25, 2023 3:33 PM
Subject: Re: bool and int
On 1/23/2023 11:22 PM, Dino wrote: > >>> b = True
> >>> isinstance(b,bool)
> >>> isinstance(b,int)
ok, I read everything you guys wrote. Everyone's got their reasons
obviously, but allow me to observe that there's also something called
"principle of least surprise".
In my case, it took me some time to figure out where a nasty bug was hidden.
Letting a bool be a int is quite a gotcha, no matter how hard the benevolent
dictator tries to convince me otherwise!