
Beyond PEP 8 – Best practices for beautiful intelligible code [video] - nharada
https://www.youtube.com/watch?v=wf-BqAjZb8M
======
linsomniac
This is the best talk from PyCon2015 that I've seen. Raymond is a great
speaker, but he really hit it out of the ballpark with this one.

Whenever I try to think "How would someone smarter than me solve this?",
Raymond is one of the people I am thinking about. I'd highly recommend this
talk.

Aside: A few days after seeing this, a co-worker asked for my recommendations
on a Python project he was working on. Which involved some Python code that
was translated over from Java. Pretty much exactly what Raymond was talking
about fixing here. I told my coworker he should watch it. A week later he
comes to me following up on it, I ask if he's watched it. No... Then he
proceeds to ask me what sort of indentation style he should use and what
format for the inline docs.

------
azeirah
Excellent talk. Would recommend to developers outside the python community as
well.

Some takeaways; 1\. Adhere to a great style guide 2\. Can you predict what the
code does? Can you trace a path through the function calls, if statements and
for loops? 3\. Can you explain to someone what the code -means-? Why is it the
way it is?

    
    
        p = (170, .1, .6);
        if p[1] > .5:
          print("bright!")
        elif p[2] > .5:
          print("light")
    

That's ok, right? Pretty nice. I can see that it'll print "light".

Good enough? No, not really. How are "bright" and "light" related to (170, .1,
.6) and .5?

How about this?

    
    
        color = Color(hue=170, saturation=.1, luminosity=.6)
        if color.saturation > .5:
          print("bright!")
        elif color.luminosity > .5:
          print("light!")
    

Far better! I know now that saturation is related to brightness, and that
luminosity is related to lightness. It takes about the same time to write, yet
is far more legible.

~~~
xorcist
The obvious question a newcomer would have to that particular code is "Can't a
color be bright and light at the same time? Why?".

Those things are better explained in a comment, I'd think.

Comments are needed, but should not explain what the code does (as in "add 1
to n") and instead exaplin why it does it (as in "fn expects indices to start
from 1").

~~~
coldtea
> _The obvious question a newcomer would have to that particular code is
> "Can't a color be bright and light at the same time? Why?"._

It can and the code in question will print both "bright" and "light" if passed
a color that matches that.

Where did you see that it's an either-or affair in the example?

Besides, the key point, is that the code talks about luminocity and brightness
levels, and the second example makes that explicit. No comments needed if you
know what HSV is. And if you don't, comments are usually not the place to
learn about it.

~~~
berdario

        if color.saturation > .5:
          print("bright!")
        elif color.luminosity > .5:
          print("light!")
    

it's an `elif`... it will never print both "bright" and "light"

This kind of mistake really detracts from the point that was argued here about
code being "intelligible"

~~~
jmartinpetersen
In the presentation it was two if's, not an if and an elif. Someone up-thread
misrepresented it.

I didn't read it carefully here, as I had already seen the presentation and it
wasn't until your disagreement I realized the code was different.

~~~
berdario
Yup... my comment about "detracting from the point" was about such an
important semantic change to slip through unnoticed. (not about the points
delivered in the talk itself or anything)

There's nothing wrong with if/elses, but I strongly prefer pattern matching,
where available. And even more, I think it's important to keep computation and
presentation separate... that is, to not entagle IO with the rest of the code.

(Unfortunately Haskell is the only language I know of that gives you a tool to
tackle that)

Obviously this was just a small example, but I've seen unintended IO byte back
the developer in real world (Python) code.

And another small comment: since I haven't bothered to comment on Hettinger's
talk before now.

I liked it (but played it back at 1.5x)... but since it's not first talk by
Raymond Hettinger I saw, I knew that his delivery is good. Some of the stuff
(should?) be obvious to every (Python) developer (but repetita juvant). I
didn't like the jab at Java for the mistake of iterating over indexes: there's
no excuse to writing that code not even there (look at the Iterator and
Iterable interfaces)

------
mixmastamyk
I recommend watching these types of long-form videos at 1.25x or faster.

For some reason youtube didn't let me change the speed of this video. Instead
I downloaded it with youtube-dl and watched it with vlc.

~~~
andreasvc
I can change the speed if I watch with HTML5; with Flash the option doesn't
show (Firefox on Linux).

------
seanmcdirmid
In my own editor written for my own work, I've implemented language-aware line
wrapping, which seems to work pretty well (it is aware of paren blocks, and
wraps them together). This is only possible since the editor is semi-
structured, but it feels like future. I've also begun experimenting with
sub-80 column lines, actually, columns whose widths are completely
configurable in real time (sometimes I want wider when focusing, sometimes I
need narrower when reading and have other things on the screen).

As an example, check out the 7th example in [http://research.microsoft.com/en-
us/um/people/smcdirm/apx/in...](http://research.microsoft.com/en-
us/um/people/smcdirm/apx/index.html).

~~~
octatoan
Nice. But, seriously, use / for division, please.

------
compostor42
Seriously tempted to print out the Pythonic NetworkElement code vs the Java
style code and put it on my wall. Perfectly embodies why I love Python so
much.

A humbling reminder of how far I have to go to be even near this guy's level.

~~~
alangpierce
In fairness, Java doesn't need to be as verbose as the "Java-style code" from
the talk, especially now that Java 8 (with lambdas) is out. Here's how I would
write the code in Java:

    
    
        runWithNetworkElement("171.0.2.45", networkElement -> {
            for (Route route : networkElement.routingTable()) {
                System.out.printf("%15s -> %s%n", route.name(), route.ipaddr());
            }
        });

~~~
coldtea
What's this name() and ipaddr()?

Sure, Java 8 has lambads, but have their disposed of getters and setters and
added some kind of properties?

If not, then the idiomatic way is not name(), it's getName().

(Of course without "unified property access", it's not that much different)

~~~
alangpierce
No, there aren't any special language features behind route.name() or
route.ipaddr(), they're just getters without the "get" name. While methods of
the form "getFoo" have plenty of history in Java, it's also fairly common to
drop the "get", especially when the class is being used as an immutable value
type.

For example, both Google's AutoValue library and the Immutables library show
examples of getters that drop the "get" prefix:

[https://github.com/google/auto/tree/master/value](https://github.com/google/auto/tree/master/value)

[http://immutables.github.io/](http://immutables.github.io/)

One argument against the prefix is that immutable value types don't have
setters, so it's not as important to distinguish between them. Another
argument is that immutable values aren't really objects in the object-oriented
sense, so accessing a field really is just a data access as oppose to an
action being performed by the class instance.

(I guess one aspect of Java that makes this less awkward to implement is that
methods and fields have independent namespaces, so nothing stops the Route
class from having both a "name" field and a "name()" method. That's possible
because Java doesn't have first-class functions, so you can always determine
from usage whether something is a field or a method.)

------
sigzero
"PEP8 unto thyself and not unto others" \--- Yes!

------
mapleoin
This is a great talk and I really like the second part where he promotes
writing your own adapters for non-idiomatic third-party libraries.

That being said, I almost couldn't get past the obnoxious rant at the
beginning against maximum line length. The reasons for the rule are made very
clear in pep8 as well as the fact that it's not a hard rule and it's fine to
override it in your team if you all agree on longer lines.

~~~
coldtea
> _The reasons for the rule are made very clear in pep8_

And are still BS with today's monitors (including laptop monitors).

Besides, PEP8 itself goes on to say: " For code maintained exclusively or
primarily by a team that can reach agreement on this issue, it is okay to
increase the nominal line length from 80 to 100 characters (effectively
increasing the maximum length to 99 characters), provided that comments and
docstrings are still wrapped at 72 characters."

~~~
masklinn
> And are still BS with today's monitors (including laptop monitors).

My 15" laptop monitor can only (readably to me) fit two 100-wide buffers in a
visually barebone editor (emacs), move to an editor or IDE where the UI takes
more horizontal space because of sidebars (Atom, IntelliJ) and the buffers are
close to 80-wide, so 80-wide is a perfectly fine limit as far as I'm
concerned.

Until I have to perform a 3-way merge, then 80-wide doesn't fit anymore.

And age will eventually catch up to me and make things worse.

~~~
coldtea
Missing the point that you don't have to have ALL your lines > 80\. Just the
few that need to be so.

And for those, you can always either wrap or scroll a little to see them in a
3 way merge, it's not a big deal.

Heck, in the eighties that you champion and that they got that rule, they
worked with a single 80-wide terminal view, not 2 100-wide side by side and no
3 way merges.

------
tdicola
I recently saw a good summary of PyCon 2015 talks that included this and a lot
of other top notch ones:
[https://www.fusionbox.com/blog/detail/pycon-2015-talks-
you-s...](https://www.fusionbox.com/blog/detail/pycon-2015-talks-you-should-
watch/549/)

------
wldcordeiro
This was one of my favorite talks from this year's Pycon, it really opens your
eyes up and lets you see the forest from the trees. It's really easy to get
caught up worrying about general PEP8 code style without noticing the non-
idiomatic code elsewhere.

~~~
agumonkey
He really built up the second part nicely with the count-the-passes video.

------
asafira
Someone posted the pycon videos a few months ago on hackernews, and this was
actually the only one I watched. What's nice about this IMO is that he's
entertaining when talking about a topic that I would normally fall asleep to.
It's not that I don't care about code quality --- my coworkers can tell you I
definitely care --- but it can be a pretty dry subject. Kudos to Raymond.

A few months ago I started to get into some networking and saw that there were
a few free online courses available. Unfortunately, despite choosing my
favorite one, I ended up falling asleep 3 times already listening to the
lectures. Man, I sound like I'm getting old...

------
harshulj
I like the indentation part of PEP 8. Especially the ways to organise
arguments while defining functions. Having a common way of writing those is
really helpful when reading the code.
[https://www.python.org/dev/peps/pep-0008/#indentation](https://www.python.org/dev/peps/pep-0008/#indentation)

------
scrollaway
One of my work projects has this huge, three-page document for style
guidelines. All the bells and whistles including the 80 character limit.

And then I realized this is all BS. I wrote a very short styleguide with a
linkback to pep8 for any "questions" one might have. _Problem solved_. You
don't need to decide every little detail of how your code is going to look in
advance, unless there is a solid reason to do so.

The styleguide, for those curious:
[https://github.com/jleclanche/fireplace/blob/master/CONTRIBU...](https://github.com/jleclanche/fireplace/blob/master/CONTRIBUTING.md)

Edit: What a great talk. Really embraces the way I've been thinking about
pythonic coding. Loved it.

------
japhyr
My code is cleaner, and much more intelligible after attending this talk.

------
rajathagasthya
This is a great talk. I attended a couple of Python training classes at work
by Raymond Hettinger and my Python code quality changed dramatically!

------
kkmickos
I always use 80 character limit as long lines makes it hard to for me follow
the flow, and it's not unusual to lose track of which line I was on when going
to the next line.

Sure there are huge monitors with insane dpi allowing a ridiculous amount of
text, but I'm not getting younger and find myself increasing font size every
now and then to be able to read.

Getting old sucks sometimes.

------
avinassh
I want to understand why makes remarks about PEP8 and core library and sending
a PR to fix them. Why shouldn't someone send a PR by changing code which
adheres to PEP8? As long as tests are passing and core library follows PEP8,
then is there anything to worry?

~~~
rtpg
I agree with this sentiment. If your policy is to keep all your code PEP8
(ideally by making it part of your test suite), then the amount of commit
messages which are "PEP8-ify" will be pretty small.

If you take a blatantly non-compliant codebase and PEP8-ify it, you'll have
many "pep8" lines in your git blame for a point, but by integrating it in your
process that will disappear pretty clean.

------
cafard
Glad to have seen this, and I will be keeping it in mind in the next few
weeks.

------
pekk
"Beyond the prevailing code standards, yet another proposal for doing things
my way instead of the standard way"

~~~
coldtea
The whole point of the talk went flying over your head.

In fact, he proposed the total inverse of what you say.

He said, code standards like PEP8 are good, and should be followed. But those
are only code formatting standards.

The beyond part wasn't about doing things "his way instead of the standard
way" but about doing things the Python way (idiomatic Python) instead of ad-
hoc or mimicking other languages you're familiar with way.

What he showed are common standard Python approaches to solving issues, taking
advantage of what Python offers instead of writing in C or Java etc style.

Really, your comment couldn't be further from the spirit and content of the
talk.

~~~
pekk
Not at all, when the talk starts out quibbling about the 80-column standard.

~~~
coldtea
That's just the intro and is said as an aside. Far from being the essense of
the talk.

(Of course this is already obvious since the 80-column thing is about PEP8,
whereas the essense of the talk is how to better structure your code _BEYOND_
PEP8's formatting rules).

Not to mention that even PEP8 concedes that you can raise the max line length
limit up to 100 if your team agrees.

------
atriix
This is some good pep talk

------
sago
One little quibble in an excellent talk: 80 cols exists for a reason. It means
people don't have to lay out their editor and shell to match your code. Your
editor can be set to 80 col, your shell can too, and then you can leave it and
it should work across languages, code-bases, and libraries. An extra line
break here or there is preferable to having to drag windows around to read
your code. At 80 cols I can get three editor windows on screen, allowing me
great views of a lot of relevant code for the bit I'm writing, or a shell in
place of one editor that I can be running tests on. Once 82 cols is okay, why
not 84, or 90, or 100? What about when the middle column needs 84 cols, and I
have to drag everything around. That's rude and productivity sapping.

I know some people program with one editor maximised and can have 200
character lines if they like, but a specific width as a convention is helpful.
And the convention that is already widely used is going to make fewer people
have to accommodate you. The 'ish' is useless in that regard.

~~~
Retra
My concern with 80 cols is that it is not friendly to dynamic languages that
allow nested definitions, or long variable names.

    
    
        if __name__ == '__main__':
            def this_is_a_function(*args, **kwargs):
                def this_is_a_helper_function(arg1, 
                                              arg2=('this line is already indented 39 '
                                                    'chars!')):
                    this_long_variable = ("Don't put an expression here unless you "
                                          "want to use useless intermediate variabls.")
                    return this_long variable if var else 'really short here'
                return 1
    
    

And some people want to insist on 8 char indents!

~~~
sago
Why not follow pep 8's indentation rules:

    
    
        def this_is_a_function(*args, **kws):
            def this_is_a_helper_function(
                    arg1,
                    arg2='this line is indented 12 chars!'):
                this_long_variable = (
                    'Don\'t put an expression here unless you '
                    'want to use useless intermediate variables')
                return this_long_variable if var else 'really short here'
            return 1
    

(for the same number of lines) or better still follow some basic common sense:

1\. Local functions should be short and have short names since their scope is
limited.

2\. Local variables, similarly

3\. Don't put long explicit strings in code.

and get

    
    
        messages = dict(
            long_default = \
                'Don\'t write strings that may wrap in ugly ways on 80 col shells.',
            short_default = 'Keep it short'
            )
    
        def this_is_a_function(parameter):
            def message(long, message='this is only 36 chars'):
                long_message = messages.long_default
                short_message = message or messages.short_default
                return long_message if long else short_message
            # Do something here.
            return 1
    

And if you have an expression that is more than 80 characters long, breaking
bits of that expression and assigning them to temporary variables is not
'useless', it makes code clearer and is only rarely a performance hit.

~~~
coldtea
If I see a "\" I close the editor and delete the source file.

~~~
sago
How impressive of you.

------
st3fan
80 columns is for old people.

~~~
pekk
Because old people are bad and lame, right? How is this kind of remark allowed
on HN?

~~~
st3fan
I'm old.

~~~
pekk
As a black man, <insert negative remark about black people>.

------
antimora
It kinda bothers me when in his presentation Raymond says make NP P. A problem
is and have _always_ been in P if there is an algorithm for the problem that
solves in polynomial time. You can have an algorithm for the same problem that
does not solve in polynomial time but this does not change the nature of the
problem.

~~~
Lord_DeathMatch
T'was a joke; Non-Pythonic vs Pythonic (NP v P)

