Hi there python-ideas - I've been teaching Python as a first
programming language for a few years, and from that experience I want
to propose a change to PEP8. I'm sure the default position for PEP8 is
to avoid changing it. However, for this one rule I think a good case
can be made to make it optional, so let me know what you think.
Let me start with what I've learned from teaching students in Java and
now in Python. In Java, you use == for ints, but you need to use
equals() for strings. Of course students screw this up constantly,
using == in a context that calls for equals() and their code does not
work right. Then for Java arrays a different comparison function is
required, and so it goes. To teach comparisons in Python, I simply say
"just use ==" - it works for ints, for strings, even for lists.
Students are blown away by how nice and simple this is. This is how
things should work. Python really gets this right.
So what is the problem?
The problem for Python is what I will call the "mandatory-is" rule in
PEP8, which reads:
Comparisons to singletons like None should always be done with is or
is not, never the equality operators.
For the students, this comes up in the first week of the course with
lines like "if x == None:" which work perfectly with == but should use
is/is-not for PEP8 conformance.
My guess is that this rule is in PEP8 because, within a Python
implementation, it is within the programmer's mental model that, say,
False is a singleton. The mandatory-is rule is in PEP8 to reinforce
that mental model by requiring the is operator. Plus it probably runs
a tiny bit faster.
However, for "regular" Python code, not implementing Python, forcing
the use of is instead of the simpler == is unneeded and unhelpful (and
analogously forcing "is not" when != works correctly). What is the
benefit of forcing the is operator there? I would say it spreads an
awareness of the details of how certain values are allocated within
Python. That's not much of a benefit, and it's kind of circular. Like
if programmers were permitted to use ==, they wouldn't need to know
the details of how Python allocates those values. Being shielded from
implementation details is a Python strength - think of the Java vs.
Python story above. Is Java better because it builds an awareness in
the programmer of the different comparison functions for different
types? Of course not! Python is better in that case because it lets
the programmer simply use == and not think about those details.
Understanding the singleton strategy is important in some corners of
coding, but forcing the is operator on all Python code is way out of
proportion to the benefit.
As a practical matter, the way this comes up for my students is that
IDEs by default will put warning marks around PEP8 violations in their
code. Mostly this IDE-coaching is very helpful for students learning
Python. For example, It's great that beginning Python programmers
learn to put one space around operators right from the first day.
Having taught thousands of introductory Python students, the one PEP8
rule that causes problems is this mandatory-is rule.
As a teacher, this is especially jarring since the "just use ==" rule
is so effortless to use correctly. In contrast, the mandatory-is rule
adds a little pause where the programmer should think about which
comparison operator is the correct one to use. It's not hard, but it
feels unnecessary.
As a contrasting example, in the language C, programmers need to
understand == vs. is right from the first day. You can't get anything
done in C without understanding that distinction. However that is just
not true for regular (not-Python-implementation) Python code, where ==
works correctly for the great majority of cases.
Here is my proposal:
Add the following parenthetical to the mandatory-is rule: (this rule
is optional for code that is not part of an implementation of Python).
So in effect, programmers outside of a Python implementation can
choose to use == or is for the "if x == None:" case. In this way, PEP8
conforming code before the change is still conforming. Moving forward,
I would expect that regular code will trend towards using == in such a
case, reserving is for the rare cases where it is needed for
correctness.
PEP8 was originally just for Python implementations, so why is this
change needed? Because as a practical matter, the vast majority of
code that is using PEP8 is not part of a Python implementation. This
may not have been the original mission of PEP8, but it is how things
have worked out.
Now we are in a situation where the rules in PEP8 are sent out to this
ocean of Python programmers of many different ability levels writing
regular code that is not a Python implementation. One could imagine a
separate PEP800 style guide for regular code, but we don't need to do
that, because in almost all cases PEP8 works great for regular code. I
have taught thousands of new Python programmers, and the only place
where PEP8 serves them poorly is this mandatory-is rule. Therefore
instead of a separate style guide for regular code, I propose an
exception for this one problem rule.
Ultimately this comes down to the question - should PEP8 push regular,
not-Python-implementation code to use is for singletons in cases where
== works perfectly? Seeing how effortless it is for programmers to use
== as their first choice, I think PEP8 should allow that practice.
Best,
Nick