Hacker News new | comments | show | ask | jobs | submit login
Beyond PEP 8 – Best practices for beautiful intelligible code [video] (youtube.com)
262 points by nharada on Aug 7, 2015 | hide | past | web | favorite | 160 comments



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.


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.


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").


>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.


    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"


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.


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)


That's not his code.


In Python, "elif" means "else if". At most one of "bright!" or "light!" will print.

  $ python
  >>> if True:
  ...   print "First"
  ... elif True:
  ...   print "Second"
  ... 
  First
  >>>


I know what elif means in Python (been doing it since 1998 -- remember Zope?).

That's not the code in his example. Here's that code:

https://youtu.be/wf-BqAjZb8M?t=40m41s


Apologies - I think we've been talking at cross purposes. I was referring to the code up-thread in https://news.ycombinator.com/item?id=10025412 , which (unlike the presentation) uses "elif".


>Apologies - I think we've been talking at cross purposes.

Yeah, didn't pay close attention to it, thought it was the same as the one I saw in the presentation.


Yeah sorry, that was my mistake in copying from the video. It was supposed to be an if statement. I'll leave it now because of the discussion on the issue


I guess Color is a namedtuple. I'm often tempted to [ab]use binding.

    def qualify(color):
        hue, saturation, luminosity = color
        if hue ... or saturation:
            ...
        ...


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.


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


You can do that with low-content videos, but not Raymond Hettinger videos.


I don't even download anymore, I pipe youtube-dl video source url to mpv (which, IIRC is obsolete since mpv gained the ability to find it with the original youtube url).


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....


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


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.


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());
        }
    });


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)


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

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.)


Yes, Java pre 2010 is a thing to forget. All the fanatic ceremony can retire nobody will miss it. All languages, as soon as they have the right linguistic construct can achieve the same level of expressiveness. Turns out first class functions were priceless, and anonymous classes weren't a good enough incarnation of that, especially in the late 90s.


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


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.


>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."


> 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.


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.


I don't think it was obnoxious. But, anytime someone is going to bring up code formatting, others will get their panties all in a twist. It's what people like to argue about when they don't want to argue about real problems.


Many years ago I worked as a copy editor. For a while I imagined, as many copy editors did, that my task was to enforce the rules of the University of Chicago's Manual of Style, especially regarding placement of punctuation with respect to quotation marks, "which" v. "that", etc. Eventually, I understood that making such changes was useful, but not really what editing should be about. It is possible to have unreadable or awkward prose with perfect comma placement, semicolon discipline, and no "which"es without a comma before them.

I doubt that I was or am nearly as good an editor as he is a coder. Yet I think that there is a logical progression (not a natural progression, since we don't all make it) from knowing the rules to knowing what the rules are for, to having the confidence to break them when it makes sense.


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...


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.


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


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...


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


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...

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


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


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!


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.


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?


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.


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


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


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.


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


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.


This is some good pep talk


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.


> One little quibble in an excellent talk: 80 cols exists for a reason.

Ayup. That reason is teletypewriters (aka ttys).

The biggest problem I have with most programmers is naming things well. 80 columns is anathema to good naming. People start using mbl instead of maxExchangeBufferLengthBytes.

No, I'm not a Java guy. I spend a LOT of time chewing through embedded C code. I don't even have good autocomplete in most embedded IDE's, and I STILL prefer maxExchangeBufferLengthBytes. Here's why--that name tells me many things at a glance:

max--limit of some form, probably should be positive

ExchangeBuffer--a buffer and it's functional purpose

LengthBytes--a length (so likely unsigned and if I see differently I should pause) in bytes (not items). You would be amazed at the number of bugs this circumvents.

That's a huge amount of information conveyed in 30 bytes. But that's almost half of 80 columns. Add in something like 8 column indents and you can't even name things well.

And, that still probably doesn't give me enough information. I need to look at that to see if that is constant, and I probably need to see if I can touch that without concurrency considerations.

I read code far more often than I type it. I read code after I have forgotten about it far more often than when it is fresh.

Naming things to enable me to come back to my code 6 years later, refresh my memory, and not screw up while doing it is the single most important task in my programming.

80 columns is simply not conducive to that.


It isn't just a historical accident. There's a good reason why they were about eighty columns. It's because the eye can't comfortably scan much further.

That's why pilots are recommended to scan horizontally no more than about 10 degrees at a time when looking out for other aircraft: http://www.skybrary.aero/index.php/Visual_Scanning_Technique


That's... true, but lines of code don't actually reach nearly 80 characters in length when you limit lines to 80 characters. Once you subtract the indentation, the remaining width of the line between the termination and the 80 character mark, and the fact that many/most lines won't be hitting the line limit in the first place, you'll find that a limit of 80 characters makes the average line length roughly 50 or 60 characters of actual code.

Having lines be too short is also a concern for legibility, because even when lines are short, there's always the risk of the reader missing the next line at every line break.

The 80 character line is actually an artifact of punch cards, which supported 80 characters per card. And that's probably a remnant of some automatic loom that for some design reason, worked best with instructions fed in chunks of 80s.


You should have the whole context comfortably within view, which means all the characters in the lines above and below should be in the same 10 degree visual block, i.e. about 80 characters.

The exact value of 80 characters might be because of IBM punched cards, but that value was chosen because printed media already had that limit, or a smaller limit, e.g. broadsheet newspaper columns. People have been writing that way for millennia.

Two other points:

(1) 70 or 90 might have been acceptable alternatives, but 80 was chosen. It's approximate. Fewer limits the amount of information per line, and more limits the font size you need to scan comfortably. A wider screen allow you to open up several windows. Having one big window isn't such a good idea.

(2) I have never been bothered by this limit, except when others break it and I have to read their code. Occasionally, sticking to it requires some thought regarding program layout. If you find yourself exceeding 80 columns often, you're probably doing something wrong. You might be nesting your code too deeply when you could call a function which handles some of your conditional logic, or your function names are too long, which suggests the underlying functions are doing too much and should be split up.


> There's a good reason why they were about eighty columns. It's because the eye can't comfortably scan much further.

Except that you are wrong.

One of the links in the comments here has research that shows that reading speed increases significantly to at least 90 characters and may increase further than that.


This?

http://psychology.wichita.edu/surl/usabilitynews/72/LineLeng...

I had to move my head with every line I read. (The PDF is somewhat easier on the eyes.) Not a single reference to aviation, the context where most of the related research has been done, and where research matters most, as people's lives depend upon it.

The article was specifically about reading news on-line, and was a very small study. Reading code is somewhat different to reading prose in natural language such as news. To understand a portion of code at all, you need to take in every token. With very long lines, this means having to move your eyes back and forward. Laying it out vertically makes scanning a lot easier.


Can you give an actual example of some well-written Python code that you can't fit maxExchangeBufferLengthBytes in?

It's a bit handwavey otherwise. I'm also a long-names fan, sometimes I go overboard, but in 20 years I've not been able to logically break my line in an obvious place only once or twice.


From current production code:

  class VendorOrderShipmentResource():
      ...

      def post(...):
          ...

          for item in data.order_items:
              ...

              if not shipment_qty: 
                  abort(400, message='All order_items must have a quantity_to_ship.')
That line goes out to col 86. I realize that it's possible to break it like this (#1):

  abort(
      400, message='All order_items must have a quantity_to_ship.')
or this (#2):

  abort(
      400,
      message='All order_items must have a quantity_to_ship.'
  )
or this (#3):

  msg = 'All order_items must have a quantity_to_ship.'
  abort(400, message=msg)
or this (#4):

  abort(400, message='All order_items must have a '
        'quantity_to_ship')
I'm not really a fan of any of those:

1. I'm not a fan of this one, in this case at least, because it "looks weird" due to the mismatch between the length of the function name, and the length of the next line. Also, I'm not a fan of "hiding" the closing parenthesis at the end of the line, rather than putting it on new line at the original indent level (like #2).

2. I'm not really a fan of this because the first argument and the function name are so much shorter than the message argument, that it looks really lopsided.

3. I'm not a fan of this because it seems stupid to create a new variable just to use it on the next line (and never again).

4. I'm not really a fan of breaking strings up this way, but sometimes I'm forced to. Breaking strings up this way tends to be really fragile when you want to modify them, and might need to reflow the entire wrap.

Personally, I'm just a fan of increasing line length to ~100. The number of things that go over 100 columns (in practice) is much smaller than the number of things that go over 80 columns.


Thank you.

Why is 3 stupid? That would be my preference. It is clear, simple and gets compiled away (in many cases). I alias in variables frequently, to make things more explicit. For example, I might write

    iterations = 300
    for _ in range(iterations):
        ...
which makes it less likely I'll end up repeating things or copy and pasting when new cases come up, e.g.

    if not shipment_qty:
        abort(400, message)
    elif shipment_qty < 0:
        abort(400, message)
What happens in your case if you come back and edit the message and add a few characters, exceeding your longer line length?

When I'm forced to break a string it is usually an indication that I need a better way of defining text than inline in expressions in code.


> Why is 3 stupid?

Just to be clear, I do use that pattern in practice, but I usually feel 'dirty' about it. Sometimes I also do things like this:

  is_admin = (membership.type == 'master')
  is_current_group = (membership.group == session.group)

  if is_admin or is_current_group:
    do_something()
but I find this easier to justify because I'm adding something more than just the breakup of a line. I'm adding semantic meaning to other developers reading the code. In the example I gave, saying "message=msg" doesn't add anything (as opposed to say "message=bad_shipment_msg", but maybe the definition of "bad_shipment_msg" pushes the string past 80 columns by itself).

As for the example of reusing the message, maybe it's bad practice, but I would end up with tailored messages describing the edge case (e.g.):

  if not shipment_qty:
      abort(400, message='Must pass a quantity')
  elif shipment_qty < 0:
      abort(400, message='Quantity must be > 0')
Edit: I do the boolean definition thing more then "sometimes" because I prefer to make complex boolean operations easy to understand, and to also convey the meaning of what you want to achieve.


I think it is pretty essential for boolean expressions too, yes, anything that isn't a single comparison, at least.

Interesting you find aliasing in variables 'dirty'.

Would you feel dirty writing something like

    def my_method(self):
        contents = self.contents
        ... etc ...
which I use often if I'm going to use self.contents a lot in that method. It has some performance benefit in rare cases, but mostly it reduces clutter, makes lines smaller, and means I type less. But again, it is 'pointless', in one sense.

From the current code open on my machine, even one character variable names!:

    w, h = self.width, self.height
    ...
Dirty? Stupid? (I'm not being facetious, I'm genuinely interested in your aesthetic sense here).


> Interesting you find aliasing in variables 'dirty'.

I don't find aliasing by itself to be dirty. It is just in this example, it would not be adding semantic meaning (as in the "named boolean expressions" example) and it would be used in only a single place (immediately on the next line) so I find it to be the least justified use of aliasing.


With autocomplete you don't get anything with "one character var names" (leave those for i, j, k etc).

And no reason to pollute the local namespace with both self.contents and contents.

What if you do this somewhere lower for example:

contents = contents[:limit]

did you mean to NOT change self.contents? Because that's what you got. Whereas:

self.contents = self.contents[:limit]

would propagate it.


> (leave those for i, j, k etc)

Why use them then if you have autocomplete? Since character variable names are useful as very short conventions, I'd never want to see them used generally. Someone working in this code would have to know the meaning immediately from the name, as for any variable. In my application area x,y,w,h,r (radius) and c (context - which is domain specific, but is present in about 50% of LOC in my current code-base) are all as ubiquitous as i and j (I'd probably not be comfortable with k, too deep nesting). i and j are much rarer in python, either using sequences of underscore for 'don't care'.

On the second point, there is reason, as I pointed out. It makes code shorter, clearer, and in some cases more performant (when contents is a property, for example). Don't get me wrong, I was following up on the specific point, I wasn't trying to recommend this style as good general practice (alias all your self variables at the top of a method - erm, no).

The lack of 'const'ing in python is a risk, yes. We use immutable data structures whenever possible, including immutable classes, because we try to ensure as much code is written without side effects on data. I'd want to not alias variables that have side effects applied to them, yes.

But you're right that it makes it easier for a sloppy edit to mess things up. In most cases the 'sloppy' would be adding the side effects at all, however, which either version has.

Still, in pages of such code, it helps to write

    cos_t = math.cos(theta)
    sin_t = math.sin(theta)
    x, y = self.position.x, self.position.y
    return x*cos_t - y*sin_t, x*sin_t + y*cos_t 
rather than

    cos_theta = math.cos(theta)
    sin_theta = math.sin(theta)
    return self.position.x * cos_theta - self.position.y * sin_theta, self.position.x * sin_theta + self.position.y * cos_theta
particularly as the number of uses of x and y increase beyond two in a functon.

Ultimately code-quality and maintainability can't be mandated by a PEP or any universal rule. But like any field, you have to understand the purpose of the rule, and weigh up its risks and benefits before you break it.


Well, for mathematics and such cases (physics etc), yes, I agree that x vs self.position.x etc is handier.

But I wouldn't ever do it for the "more performant" part, unless I have profiled the code and it indeed makes a non trivial difference (I know aliasing to a local makes a difference it itself - but I mean it should be significant when the whole program is taken into account, even if it was 1000x faster to access the aliased local, it wouldn't make sense to optimize a part of the program with it, if said part is only responsible for 1% of the total running time).

For the general case, I suggested i, j, k only because they are well known conventions, so their meaning will be instantly understood (and of course, if one can avoid such indexes altogether, e.g. with a "for item in" loop, one should).


I think 3 is bad because it is more complex than the natural code. It's not incomprehensible, of course, but clearly more complex.

I like introducing named variables for readability a lot. But this doesn't help readability. It just adds complexity for the sake of fitting into 80 characters.


> But this doesn't help readability. It just adds complexity for the sake of fitting into 80 characters.

But 'for the sake of' implies that it has no other purpose. But the purpose is readability. It will help readability for the vast population of programmers who have 80 col editors or shells, and who code according to PEP8, won't it? Isn't that the point? Of course you can say 'It would be more readable if you guessed my window width preference correctly'. But what should I guess? If I look at your code and see a 90 col line somewhere, how do I know you won't drop a 100 col line in and hurt the readability again? Do I have to read your README to find how big to make my windows? Or do I just take the readability hit for the sake of your preference?


1. I don't remember when I last ran into anyone who voluntarily limited their code to 80 characters. I doubt it was this century. I worked for a while at a Major Company that had an 80 character coding standard. It was universally despised on my team, where everyone had 2x27" monitors.

Clearly you work in a different environment with different standards. I think more or less formal coding standards are important for any dev team. But they can be very different in different teams. Don't assume what you have grown used to and comfortable with is some universal truth that must fit everyone for all times.

> But what should I guess? If I look at your code and see a 90 col line somewhere, how do I know you won't drop a 100 col line in and hurt the readability again?

If we work on the same team, that is a discussion we'd need to have. Until then, let's continue being happy in our respective circumstances, OK?

2. By "Readability" I mostly mean "cognitive load" for the human reader of the code. What to fit in a line is mostly decided by what's an easily digestible chunk. If you can fit "one thought" into one line, that's ideal. Line length is a factor, but just one of many, not one that overrides every other.

So, come to think of it, I actually would break out a variable solely for line length reasons. Absolutely not for the sake of 1 character, but probably for 20.


It will help readability for the vast population of programmers who have 80 col editors or shells

Isn’t that the premise that is being challenged here, though? There’s plenty of variety in which editors and shells experienced programmers prefer to use, but do any of those tools really still have a hard 80 column limit in 2015?

I would guess most developers now use screens that can show at least two (and often three or even four) source files side by side and still cope with longer lines than that, and I would guess most could switch their editor or shell to cope with those wider lines in a fraction of a second with a single keyboard shortcut.

I can see cases where line length could still be a limiting factor, but I’m not sure giving up general readability improvements from allowing somewhat longer lines so it’s easier to do a three-way merge on a laptop with a smaller screen is a good trade.


Nobody is suggesting that people Can't view more than 80 cols. But many people have their machines and environments set up for 80 cols. They have their windows laid out based on the code they're writing, and then they load a new file and have to drag and resize their environment to accommodate you.

If there's a way to change window size and position from 3 columns of 80 + a project browser into 120 col with a single keypress, then I'd like to know. It isn't a major problem, but it is an unnecessary problem.

Nobody is forced to use long lines either, and if you want to lay out your environment to support 120 cols and you get my 80 col source code it will work without even a keypress or a second thought. You won't even notice it.


If there's a way to change window size and position from 3 columns of 80 + a project browser into 120 col with a single keypress, then I'd like to know.

In case it’s of any interest:

I use Sublime Text as my main editor. One of its nice features is that you can switch how the window is divided up with a single keyboard shortcut or menu command (View -> Layout). You can also easily define custom layouts in addition to the standard 2/3/4 columns, 2/3 rows, and 2x2 grid. I usually run with the editor maximised on my largest screen and 2–4 different panes open. The one feature it’s missing in this area that I’d really like to have is similarly clean support for multiple windows and therefore multiple screens. I’m not an Emacs expert, but colleagues who use it regularly do seem to have similar features available.

I also use a tool called WinSplit Revolution, which provides a somewhat similar feature for general Windows applications, letting you define some preset regions of your screen and then snap the current window to any of them with a quick keyboard shortcut. It can also shift windows between multiple monitors if you have them, again with a single quick shortcut. I can therefore instantly resize windows for things like shells, history/diff tools, and so on if I need them to be a bit wider for whatever files I’m currently working with.


Have you thought about:

    message = "Shipment seems fine"

    if not_shipment_qty:
        message = "Shipment is not fine"
    elif shipment_qty < 0:
        message = "No quantity"

    abort(400, message)


That is semantically different. It always calls abort(). In this case abort() raises an exception that returns a HTTP 400. I'm not going to abort if everything seems fine. :P

If you wanted to do this pattern, it would look more like this:

  message = None

  if not_shipment_qty:
      message = "Shipment is not fine"
  elif shipment_qty < 0:
      message = "No quantity"

  if message:
    abort(400, message=message)
(Note: In this case the keyword argument form of message is required, because all keyword args get packaged up into a JSON body of the response.)


Just let the line run long. These are only guidelines. There is inherent wiggle room. I break lines that feel too long and casually ignore the 80 column margin. Inserting unnatural breaks is just as bad as excessive line length.


It's different if you're using a tool (e.g. pep8) to ensure coding style. You can tell it to ignore long lines, or you can configure it to have a "better" line length than 80.

Telling it to ignore all long lines means absurdly long lines are accepted too, but configuring it for a particular number makes it a hard limit. The best option is to pick a number that is a good trade-off.


In my case I am a fan of:

    abort(400,
          message='All order_items must have a quantity_to_ship.')
(not giving the parens an entire line)

I'm not a fan of 80 characters, but I am a fan of less than 120 characters, if simply that there is a point where a line won't fit in a terminal thats in half of a "standard laptop" screen (i.e. the limit to where I could put two files next to each other)


This is why I dislike Pythons standard of using four spaces for indentation. By the time you've declared a class, a method and a for-loop and a conditional you're already 16 characters down and struggling to fit code into the remaining space.


Regarding your last point, it's iteratively true. The number of things that go over 120 is much less than the number that go over 100. One always seems to need just a little more space.


I wasn't very clear, but I meant to say that the number of lines that will naturally end up between 80 ~ 100 columns is greater (in practice) than the number of lines that will go over 100 columns. I.e. I think that 100 is a better "sweet spot" than 80 or 120.


If you add two of those variables and assign the result to another variable, you're already at about 96 characters before considering whitespace. I don't think it's that hard to exceed 80 characters doing very simple things.


You mean

    this_is_my_very_long_variable_name = (
        this_is_one_variable_that_goes_into_calculating_it + 
        this_is_another_variable_that_needs_considering)
The issue wasn't the fact that some expressions are longer than 80 cols (that one is longer than 120, even, its 136 characters minimum), but that they can't be clearly and appropriately written in 80 cols.


That example is pretty trivial, but I'd hate to read code where every other logical line is broken up into multiple. It breaks up the flow of the code and makes it much harder to read, especially with how the indentation constantly changes (which is especially important in a language like Python, because I've trained my eyes to the special meaning of whitespace, so seeing non-significant indentation adds additional noise).


Right, but again, can you see you've just gone abstract and handwavey. I'd also hate to read code where every other line is broken midway through an expression. Can you give an example of code that 80cols would force that on, which doesn't have deeper issues of clarity and structure?

It's not a trick question. I've written millions of lines of code over 20 years, and I've been renowned for using overly long names (compared to most Python coders), but I've not found that issue. Some breaks, yes, but never 'every other line', or even nearly that.


You're right, I don't write much Python anymore and don't have an example on hand. But I write Swift for a living now, and I know that if I restricted my lines to 80 characters wide, I would have to split up a lot of lines, including most method definitions. I much prefer the long lines, because if the details aren't important, they're easier to skip, and they're much easier to scan through when you're trying to read a large amount of code at once.


Thanks, its a good point. I've only played with swift, but I've written a fair amount of objective C, and I didn't put 80 cols in coding standards for my company for that. We got away with that because the environment was fixed. And the path of least resistance was to use it in the way Apple told you to. You couldn't even split XCode more than two ways back then (iirc). So the issue of different tools, different screen layouts, and different workflows didn't raise. So yeah, 80cols isn't a panacea across all languages.


Can I ask about a similar real problem I had a few times? How would you format this code?

    class Batman():
        # ...
        def handle_jokes(self, villains):
            for villain in villains:
                if villain.supports_jokes:
                    formats, transports = villain.query_joke_formats_and_transports()
                    # ...
That long line is 82 characters. Assume there's a good reason formats and transports are queried together. In practice this leads to variable names f and t. :(


    query = villain.query_joke_formats_and_transports()
    formats, transports = query
or

    formats, transports = (
        villain.query_joke_formats_and_transports())
or

    formats, transports = \
        villain.query_joke_formats_and_transports()
Of which, we tend to do the first.

Again, the longer version is clearer and simpler, but the shorter version is not so confounding that it is a slamdunk argument for longer lines, particularly as, for any length line, you could get this problem, so you'll have to do something like it eventually. If you're seeing this all over the place, it may be worth wrapping the API in more pythonic terms. 'Getters' taking no arguments, for example, are often a code-smell in python, though queries (as in your case) are a good exception, since it is also not great to have properties do expensive work (like querying a DB, say).


In reality there are multiple arguments to these functions, I just omitted them here to simplify the example.

What other more pythonic terms could be used? The proposed rename to jokes is completely unrealistic.

It seems kind of sad to butcher such nice simple code for these artificial non-reasons.


I would rename query_joke_formats_and_transports to jokes.


What if that's part of a published interface? One that maybe also contains things like query_joke_history(), format_joke(), transport_joke() and execute_practical_joke().


If it's painful enough, I would write an adapter as done in the video.


> Can you give an actual example of some well-written Python code that you can't fit maxExchangeBufferLengthBytes in?

Sure:

thisIsAnOutgoingBuffer = this_is_a_function(descriptiveKeywordArg = maxExchangeBufferLengthBytes, ...)

It's been a while, but I seem to recall that Python would require a continuation character to break anywhere prior to the comma.


No continuation character needed

    outgoing_buffer = a_function(
        descriptive_keyword=max_exchange_buffer_length_bytes
        ...)
Breaks nice and semantically. Calling functions with arguments on new lines is very pythonic, so much so that it is a lot of the examples of indentation in PEP8. For functions with more arguments, it is readable for the same reason that you might want to define variables on successive lines.

Interestingly, notice that in your quick back-of-the-envelope example your variable and function names are quite redundant. I know it was throwaway and it wasn't your point: I'm not suggesting you were holding it up as good naming, but it is interesting that the toy examples being quoted have to work quite hard to make it bad. That suggests to me that a lot of the problem is manufactured, in practice.


Huh? I could have sworn that Python didn't allow a break after a function call. There is something odd in the grammar that does weird things that I have tripped over that forced me to use a continuation character where I really wanted to just use a line break. And, it should be Python because what I'm remembering would need to be a whitespace-delimited language. I'll leave it up to the language lawyers to find. :)

> Interestingly, notice that in your quick back-of-the-envelope example your variable and function names are quite redundant.

Agreed.

The keyword argument is likely to specify things like "maxBufferLengthBytes" even as the variable does. The problem is that they serve two different purposes. The variable is moving around the program and needs to carry it's meaning with it, while the keyword argument serves to document the API that the function is part of. Because they are orthogonal, they are redundant.

In the end, the goal is productivity. I can live in 80 characters if I have to, but, if I'm in charge, it's 120-130.

Raymond's warning about reformatting introducing bugs is spot on though.


This is how I do stuff like this, and I very rarely have to use funny line-continuation characters:

    thisIsAnOutgoingBuffer = this_is_a_function(
      descriptiveKeywordArg=maxExchangeBufferLengthBytes,
      more_long_param=a_nested_function_call_with_long_params(
        inner_param=55,
        another_inner_param="Asdf"
      )
    )


>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.

Yeah, that was nice for 80 line terminals in 1986.

This is 2015. We have 27" screens. Two of them for most of us.

And on our lowly laptops, we have hi-dpi fonts (which makes smaller fonts sizes read great) and widescreens.


Right, and that means we can have more code on screen, and docs and tests, and shell. Where is the rule that you have to have one window open at a time? That's the real throwback to terminal interfaces.

The number of programmers I see manically toggling through their code in one window is crazy. I think this is part of the legacy of some high-profile IDEs that gave you one window at a time.

What proportion of your code lines are > 80 cols? Multiply that by the amount of extra width to get the wasted screen estate. I'll take that and put more code/docs/tests/output on my screen at the same time and have to toggle less.

The idea that this is about teletype is very amusing, but rather naive.


>Where is the rule that you have to have one window open at a time? That's the real throwback to terminal interfaces.

Even on a widescreen laptop you can have 2 > 100 lines windows side by side. And for multi-monitor setups you can go even wilder.

>The number of programmers I see manically toggling through their code in one window is crazy. I think this is part of the legacy of some high-profile IDEs that gave you one window at a time.

If you have tons of junk in front of you, you're not focusing on your code as you should be.


Right, I can fit 2x100 cols, or 3x80 cols + a project view. So I can see my code, its tests, and either the shell (i.e. test results, ipython, debugger, tail -f logfile) or a web browser for documentation.

Is that junk?

How many of your lines require that 100 columns, in your average code?

Of course, this can just descend into a pissing contest. The point isn't who-has-the-most-windows, but that the logic of 80cols has a practical point, and programmers who continue with the default have reasons that aren't just about teletype or not moving with the times.


>* So I can see my code, its tests, and either the shell (i.e. test results, ipython, debugger, tail -f logfile) or a web browser for documentation.*

Did someone stole the lower part of your screen? Or do you have all views in parallel, instead of say stacked vertically?


I could cut half of my editors off, of course. But then I'm loosing even more context. And I have a shell output that is full width but not very tall, so I can't see as much context, and I have to scroll my code more. Again, this isn't a pissing contest. The point is that there are reasons people prefer it. What are you trying to argue? It seemed you were trying to suggest it is purely a historic throwback and pointless.

It all comes back to this question: what proportion of lines in your code use more than 80 cols? If it is a small proportion, the geometry is simple: you waste more screen by having longer lines.


>It all comes back to this question: what proportion of lines in your code use more than 80 cols? If it is a small proportion, the geometry is simple: you waste more screen by having longer lines.

It's obviously always gonna be a small proportion. Nobody write > 80 lines all the time (or should).

But just because you accept > 80 lines doesn't mean you have to have the editor to > 80 width. You can just let it either wrap them or cut some lines off and scroll when you want to check them (what I do).

I don't buy that somehow this "80 characters per page" is some magic number that holds true from the teletype days to today, and it should be respected regardless of font size, monitor width, etc.


> it should be respected regardless of font size, monitor width, etc.

I don't think anyone would suggest it is magic. It is a convention that is somewhere near to being good, and is so widely used that it is heavily tool supported, so you should have a good reason not to use it.

Actually, 80 is a bit of a misnomer, PEP8 has it at 79, git convention is 72 (50 for first line, to allow git log to display sha-summary inline and fit into 80 cols), etc.

> You can just let it either wrap them or cut some lines off and scroll when you want to check them (what I do).

Ah, I see. In which case I take back many of my objections. I see what you're saying now. Thanks.


I rarely find myself wishing to split my screen. It's not that I don't know that I can, and occasionally I will (especially if two pieces of code happen to be VERY tightly coupled, with lots of passing back and forth between the two). In general, however, I find that since I am only reading one line of code at a time, having two editor windows up is pointless. It's like having two browser windows instead of two tabs in a browser window.

Plus, with most editors that can jump in / out of functions, it's not like I'm losing my place. In fact, my editors all save my place in files on exit.


Interesting, do you do much unit testing for code you write?

And you know you can put different parts of the same file in columns too? I often need to write code that is coupled to another part of the same file.


Unfortunately, at my current job, we don't seem to believe much in unit testing. There's some indication this may change in the near future.

Additionally, I have two screens, and since I mainly use a tiling window manager, 80 columns works... okay. But 80 columns isn't usually where my splits end.

Interesting point with the same file in columns. It's rather that I do that. More often I'll be looking at the same file across two branches. I am kind of surprised that we don't see more plugins doing 80 column lines, in sequence, to fill the screen however. More lines on the screen seems to be the craving that vertical monitors + high-res monitors aim to satiate.


80 columns of text is wonderful in my dual window vim with NERDTree on the left. All my screens are some version of the 1680x1050 aspect ratio and it fits perfectly. I'm always using 2 windows for simultaneous code/test writing, diffing, and multiple windows into different parts of the same buffer, multiple files open etc.


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!


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.


Those are great suggestions, but may point is more that "too much on one line" isn't necessarily better than "too little over too many lines." It can be hard to get a good overview of what is happening when you've got to resort to splitting one significant token per line.

In other words, I try to use vertical space for higher-level work than horizontal space, and when you have to fit both into vertical space, you lose some clarity in high-level in order to gain it in low-level.


Sorry, I know that putting code up is an invitation for people to pick at the wrong feature, so I realised I was being churlish.

But I think these things do have to be addressed with examples. There are few people willing to put an actual example up that a) is frequent enough to mean that 80cols can't be easily used (note, not 'preferred', we're talking about a standard, plenty of people 'prefer' 80 cols) and b) is pythonic enough that it isn't better written in more explicit steps.


Eighty columns is a good standard, I just think people forget how small it can be, and why it isn't always a problem. I've written tons of code that looks fantastic, if only I could use 85 columns, but rewriting it to use less just makes use of some pretty clunky constructs. All these extra "()"s and "/"s aren't actually helping make the line more readable, it just makes it fit into a rather arbitrary column limit. And at that point, you'd be thinking that the best way to make your code the most readable it can be is to use more columns.

So I don't think 80 cols is a hard limit, anymore than I think writing code in a terminal is a hard limit. I use a non-terminal text editor. I do it because it makes it easier to read code and format it how I like. I see little reason why anyone should be jumping through hoops to accommodate that. By using a terminal editor, you've already decided you won't get the best formatting, because you sacrifice the flexibility that allows it in exchange for something else. You should be expecting things to wrap around awkwardly on occasion.

Eighty columns is a good target width, but it's not worth proliferating clunky constructs to conform to. That's no better than having code wrap. (Of course, someone could also write terminal editors that allow text to go longer than 80 lines. Why are you using an editor like that if it can't do something this simple?)


Thanks again. I agree, I've written a lot of code that would be clearer in 85 cols than 80, and some code that would have been clearer in 160 cols too.

I think we're agreeing mostly.

The problem with 'ish' is that I see it as worse than useless. 80cols-ish is what? 90 cols max? Why not just use 90 cols as the standard? If I have to scroll my whole window or resize it to read your line, is that really better than if it had an extra break? Some people may think so, but I don't, personally.


Ok, cool. What I do is just put a column marker at 79, make my window 82 cols wide, and then just write it as beautifully as I can. No hard limits. Just the natural "I can't read that over there, I should maybe rewrite it."


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


How impressive of you.


Then use better whitespace rules. Not to mention the helper isn't capturing any closure here so it's not particularly useful inline, and even when they are you can refactor variable capture to new functions. Nested definitions in python are pretty rare, and oft unnecessary

    if __name__ == '__main__':
        def this_is_a_function(*args, **kwargs):
            def this_is_a_helper_function(
                arg1, 
                arg2='this line is now indented 12 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


Surely the fact that there are two typos in your code, one of them in the name of a variable (`this_long_variable` vs `this_long variable`), indicates that things can go wrong when you abstract out a literal to a variable?


I literally copy pasted from the other guy and added whitespace.


To quote the Zen of Python:

    Flat is better than nested.
Too many levels of nesting is definitely a code smell. Often it's better to pull those helper functions out, and/or create function or method factory functions at a higher level of organization.


You can't really do that if you're writing closures.


Have you had a look at https://docs.python.org/2/library/functools.html#functools.p... ?

Anywho, do you have a genuine example of where a closure is helpful for you in python? I'm very curious.


I don't understand the question. Your link has examples of closures right in it, so naturally if you're doing anything like that, you'll want them.


One size doesn't fit all --- if a particular language culture is focused around shell terminals, it'll probably go for 80. If it's focused around IDEs, like Java, it'll probably be about 100.

(Go, for some reason, doesn't like splitting lines at all, no matter how wide. I've had code reviewers criticise me splitting lines at 200, which I don't understand at all.)


There's a certain point where an expression becomes difficult to read, because it's too long. If you're pushing 100, it likely means you should separate the logic out into a few smaller expressions.


When you have a function with a large number of parameters, splitting into expressions does not help, but splitting over multiple lines looks much clearer.


Word processors have soft-wrapped since like forever.

Recently code-editors have started to learn how. Don't wrap your lines at all; let the editor do that, in realtime, and you can have your windows at whatever width you want.


> 80 cols exists for a reason

As far as I can tell, that reason is the IBM 80 column punch card standard launched in 1928:

https://en.wikipedia.org/wiki/Punched_card#IBM_80-column_pun...


Only the first 72 columns were available for code. The last 8 were reserved for the collation sequence. Which was handy if you dropped your card deck.


I agree that a standard is useful. However, monitors have changed drastically since the 80 column standard was agreed upon. I'm fond of 120, I think it strikes an ideal balance.


So set up at 120, and then look at someone's code that's used 128 consistently. And then reformat for those few lines that went that long. See the point?

You can't standardise based on what you are fond of. That's the point of a standard. When such a large proportion of people, and the standard library, and most shells, use 80, then using 120 will inconvenience them. If you load my 80col code into your 120 col editor, it will not inconvenience you at all, barring an occasional extra line break.


>So set up at 120, and then look at someone's code that's used 128 consistently. And then reformat for those few lines that went that long. See the point?

No.

>You can't standardise based on what you are fond of.

Sure you can. That's why company and team-wide standards are for.

Nobody has to be forced to use some BS 70's throwback rules just because they are in PEP8.


I get that. But a large section of the Python community has standardized on 120, and I'm adding to it in hopes of hitting critical mass.


In your average code, what proportion of lines of code are > 80 cols?


    >>py34 lns.py
    total lines: 2099
    0.063% over 80
Not many apparently, and a significant portion of them are hard coded URLs/strings in scripts. I guess I stand corrected, 120 isn't that useful...

    import os

    from pathlib import Path

    def walklines(glob='**/*.py'):
        for filename in Path(os.getcwd()).glob(glob):
            with open(str(filename)) as file:
                for line in file.readlines():
                    yield line

    if __name__ == '__main__':
        alllines = [line for line in walklines()
                    if line]

        totallines = len(alllines)

        cutoff = 80

        total_long_lines = len([line for line in alllines
                                if len(line) > cutoff])

        prcnt_long = total_long_lines / totallines

        print('total lines: {}'.format(totallines))
        print('{:.3f}% over {}'.format(prcnt_long, cutoff))


One thing I find that makes a big difference is using the PEP8 indentation rules for writing lines of the form

    variable = some_function((some nested expression that is very long
                              and needs to wrap))
as

    variable = some_function((
        some nested expression that is very long but may not need to wrap
        but if it does there's tons more room for it))
I.e. you don't have to differentiate between 'syntax indents' and 'expression indents', every thing is just an indent of the same size. Which has the advantage that almost every editor can indent it correctly, and it works with both space and tab indents, whereas you're at the mercy of your Python editing mode whether the 'indent to sibling' works for everyone (and if not, the programmer has to sit tapping space to line it up right). Both approaches are in PEP8, but i find that simple change removes 99% of all >80 line cases for me.

The only caveat, also covered in PEP 8 is for function definitions.

    def some_descriptive_function_name(one_parameter,
                                       another_parameter):
        some_functionality()
becomes

    def some_descriptive_function_name(
            one_parameter, another_parameter):
        some_functionality()
i.e. the parameter lines are double indented.


Double indentation looks rather ugly though. I like the "K&R" style much better (as shown in comment from bpicolo):

    def some_descriptive_function_name(
        one_parameter,
        another_parameter,
    ):
        some_functionality()
Anyway, either one is superior to 'indent to sibling', where the lines are now tightly coupled to each other.


We each have different tastes, yes.

But, coding standards aren't about tastes, they are about coordinating large numbers of programmers to write code in consistent ways. PEP 8 gives the 'double indentation' as standard, rather than the 'K&R' style.

You're free to write however you want to, and if you're the tech director of a company, you can tell everyone else to follow your aesthetics. But you'll be doing a lot of work with code written according to PEP8. In my experience, learning and disciplining your team to use the standard is better than having a house-style. But YMMV, of course.

PEP8 isn't my 'ideal' aesthetic for Python either, but I'd need a far better reason than 'I think that looks ugly' for not using it.

I also agree 'indent to sibling' is poor, and not very universally tool-supported, even though it is part of the PEP8 style.


I don't see the problem. There are aspects of PEP8 which I don't like, so I don't follow them. Why would you need to convince others of your coding preferences?


Optimal readability is attained with 60-70 characters. This is due to human psychology, and technology such as monitor size does not change it.

When lines are longer it becomes more difficult for your eyes to keep track of where the next line is. Furthermore, code is not formatted as paragraphs but as separate lines, so you end up wasting a lot of screen estate for those few long lines. Having a low maximum means it will be close to the average and a larger proportion of the screen is utilized.


> Optimal readability is attained with 60-70 characters. This is due to human psychology

Actually this claim is disputed: http://psychology.wichita.edu/surl/usabilitynews/72/LineLeng...


Interesting. It might be that reading from screen works differently than from paper, where the 60-70 limit is a tradition. However, reading news is very different from reading code, so it doesn't go without saying that this result can be generalized to code.


My MBP15 with split panes only fits 96.


> 80 cols exists for a reason

I like to joke God made The VT52 with 80 columns because that's how terminals should be.

Another I use is that "80 columns should be enough for anyone".

Now, seriously, code that's too wide (or too long) is a code smell. You probably should name your variables better, have fewer them in scope or just refactor the code to be more readable. Remember: code is executed by very cheaply and read by very expensive humans. Optimize for the latter.


Another reason that 80 cols mattered was because code could be printed properly on an 80 col dot matrix printer - way back then. Today, you can set your editor/ide to wrap it for you and you should - just 80 is such a waste of space on a modern display.


> 80 is such a waste of space on a modern display.

You're assuming you have just one window open, aren't you? There's less wasted space with 80 cols if you have multiple columns (of the same file, or different files). The math is elsewhere in this thread.


Python frequently gets away with 80 because you don't have 8 characters of wasted indentation for namespace and classes as you do in say C# or Java. But then again it compensates for that by adding underscores_in_every_variable_name. Anyway, for me anything below 100 just encourages violation of the rule or crappy variable naming, you can still have at least 2 files + project explorer open per monitor.


When people don't wrap at a reasonable width, IntelliJ's soft wrap settings are the next-best thing:

Settings > Editor > General:

* check "Use soft wraps in editor"

* check "Use original line's indent for wrapped parts"

* enter 4 for "Additional shift"

* if you open huge files with wide lines, check "Show soft wraps for current line only" to prevent slowness


Are… are you a wizard? I didn't know about this setting, thanks, I'm pretty sure it's going to change my life for the better.


I'm sure you know it's an old design decision that was practical at the time. 100 years from now are we still going to be stuck with 80col's? In your example making the interface smarter could remove the need to manually resize boxes.

I like standards, but 80 chars just isnt enough and never was. Is 96 the next reasonable number?


80 columns was chosen because it fits well with documents produced for old-style fixed-with manual mechanichal typewriter paper. (If you look at the old text files, like the oldest RFC’s, they match this style, and early terminals were made by hooking electric typewriters to computers and supplying a very large spool of paper.)

I’ve seen 66 characters recommended as a maximum line width as a style guide for typewritten documents. You also want some extra room for extra margins, line numbering, etc. If 66 is taken as a good minimal number, then 64 (2⁶) is too small, so let’s add, say, 16 to 64, giving 80 columns.

Paper documents have the form that they do for a reason. You never saw someone writing sideways on a paper (landscape alignment). This is because readability suffers when lines are too long. Even if boxes resized automatically, it’s the line length that’s the problem, not the resizing or scrolling.


'Stuck with'? I don't think we're stuck with anything. I think 80 cols is a very practical width.

Most lines in code that is well structured and simple are less than 80 cols wide. Lines that require more than that can be broken. I think in 20 years of Python I've only seen a couple of cases where there wasn't an obvious semantic break point, most of the time such breaks are easy to place at logical points.

When you have 80 cols you have more code in your window. You can use the resolution to have taller windows and more windows side-by-side. 1920 pixels gives you nicely 3x80 col editors. Which allows you to look at the code, and its tests, and the shell at the same time, for example.


"1920 pixels gives you nicely 3x80 col editors"

Depending on your font. I use 1920 (-Misc-Fixed-Medium-R-SemiCondensed--13-120-75-75-C-60-ISO10646-1), and I get almost 4x80 col's, 3x96 works nice.


Right, I have a pair of 1920s portrait so I can have more drops on my desktop, but on my 17inch MBP, more than 3 drops is too small for my middle-aged eyes.

As the commenter above stated, he found considerably less than 1% of his lines required > 80 cols, so rather than go 96 cols and have 17% of my screen real estate wasted, I'll have the extra column of code or documentation or tests, or output, and have to toggle less.


80 columns is for old people.


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


I'm old.


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


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.


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




Guidelines | FAQ | Support | API | Security | Lists | Bookmarklet | Legal | Apply to YC | Contact

Search: