If I could amend PEP 8
kennethreitz.org
kennethreitz.org
For strings that are meant for human consumption, use double quotes, otherwise use single quotes.
This is super practical when looking strings meant for translation, end-user formatting, and such.
I'm fairly sure that single quotes are much more common in the UK in literature, though, so this only feels like it makes sense to NA and AU speakers.
It's just that the primary/secondary role is reversed. (This is also reflected in which one you have to hold Shift for on a computer keyboard.)
A bigger issue IME is languages (mostly of the C family) where single-quoting is for character literals.
Also in Smalltalk comments are double-quoted, but that's a pretty rare language to encounter.
80 characters helps a lot since you can count on all code to fit within a certain area - so you can run three side/side text buffers in your text editor, instead of two with lots of useless white space because a few lines might be too long.
Doing a simple overview of the requests library, most of the lines over 80 characters are just laziness such as:
https://github.com/kennethreitz/requests/blob/master/tests/t...
And a few of the actual potential cases for going over 80 characters can still be broken down without losing any readability:
https://github.com/kennethreitz/requests/blob/master/request...
r.headers['Proxy-Authorization'] = _basic_auth_str(self.username,
self.password)3 side/side buffers is arbitrary, (it would be 2 on a small laptop display) - and maybe that's why I like 80 characters, it lets me develop on any screen without needing more real estate because the files are long.
I mean Angular has iirc 120 characters, and if you take a look at an average source file eg:
https://github.com/angular/angular/blob/master/modules/%40an...
You'll see a ton of white space after 80 characters that is 'wasted' - this also eats up into horizontal real estate of another buffer which in the end means you actually have less information on the screen with >80 characters rather than more.
In all cases - the code in that file could easily be broken into multiple lines and not lose any readability.
It's about 1/3 of my 13" 2013 Macbook Air - the other 2/3 is usually a browser.
It's also not even about how much horizontal space there is for any reason - it just scans better if you keep it narrower.
Does anyone else feel this way? Or I like it because I had to do it and therefore had to like it in the process.
Then I was assigned a project where this was enforced in the test suite and had to religiously follow pep8. It took a while to get used to but after a while the benefits (like fitting into everyone's editor configuration, cleaner list comprehensions etc) became apparent.
Now I'm the one to put flake8 as a part of the test suite in any new python project :)
Yes, it can. It also might end up being: a) less readable, b) uglier
Resources are limited so I'd rather devote my efforts to fixing major styling problems rather than a line that goes over 3 characters
Having a hard limit is overblown nitpickness (and even the 1st line of Pep8 warns you against those)
Not to mention how to do line continuation involves different conflicting styles
find . -name '*.py' | xargs grep -n '^.\{80\}'
and post it here.But it's stupid to break a line like this in two
stuff.do_something_funny(abc, def, ghi)
when the limit is reached at the 3rd parameter (or worse, at the parenthesis)
Don't get me wrong, I personally think 80 is a fine number and it's what I use myself. But making things like this hard rules for what basically are arbitrary reasons (e.g. depending on screen resolution) doesn't seem right in my book. I'm seriously not even considering doing something about a line if it's 81 characters.
As for python, some fancy list comprehensions get rather long rather quickly. Especially if itertools are involved as you izip, etc. Or using useful variable names (i.e. not 'fcnt', 'tcnt') while destructuring as in this example from pyspark/mllib:
(failure_count, test_count) = doctest.testmod(globs=globs, optionflags=doctest.ELLIPSIS)
I adapted your grep to:
find . -name '*.py' | xargs grep -n '^ *.\{80\}'
So leading indentation doesn't mess with the results.Sure, and we all know that indentation in Python is not allowed for list comprehensions.
class Foo:
# ...
def bar():
# ...
if baz:
# ...
result = [
y.strip()[1:14].replace("this", "that")
for x in nabla.generate(q, w, y, z)
for y in x.something_other()
if y.has_property(...)
]I think that's just as reasonable as the rest of Python's whitespace usage, since it (hopefully!) causes the programmer to consider whether that ceremony (classes, methods, etc.) is neccessary or just overcomplication.
It's directly comparable to, say, nesting lambdas in lambdas in lambdas; probably not great for readability, etc. It just-so-happens that in Python's OO, that first lambda is called a class and the second is called a method (objects are a poor man's closures, and closures are a poor man's object!)
hn is such a cool place. :)
I've found that in the absence of a hard limit, you all too quickly end up with a codebase riddled with 250+ line monsters forcing you to scroll right and left all over the place just to get the faintest smidgen of an idea of what's going on. It's a maintenance nightmare.
Meanwhile, GitHub won't show lines longer than 132 characters (on Windows) or 123 characters (on the Mac) without scrolling, no matter how wide your screen.
I personally find 100 seems to strike the right balance.
C tends to be terse, so easy to imagine things under 80
python (due to lack of decent types/more verbose community) has more of a need for those 80 chars.
I think there's likely a per-project line limit that "makes sense".
I typically go with 'about 1/3 of my screen width' so I can develop in multiple windows without horizontally scrolling. That's a lot more than 80 chars on a 4k screen.
Add the fact that there still are people who print the code on paper out there.
I did a search through our codebase for line lengths over 80 or 100 characters and found remarkably few. Most were comment lines.
Just do whatever you feel like. If your editor, linter, or review process makes you change it, those things are broken.
The fact that the codes works is most important, but being nice to work on comes a close second.
As for strings, meh. But consistency is nice. Line length exceeding an arbitrary standard, fine. Rules can be broken if there's a good reason.
As a smug lisp weenie that has been working in python for many years, I completely disagree with this.
> you just waste time re-justify everything if you refactor.
A single `indent-region` in emacs and you are rejustified, no trouble.
> It's just more effort in the long run, and for what?
It's more effort as opposed to what, exactly?
> It isn't prettier, more readable, or more convenient.
It is, to me, prettier, but I think, objectively, it is more readable than alternatives, especially if there is any kind of nesting involved.
I concede that if there is nesting involved, you might be bumping into other python style issues, and generally might want to add some intermediate variables, etc; however, I do believe that in at least some cases this is entirely inconvenient, and so the lisp way of aligning parameters with their delimiter is the way to go in those cases. Anything else would be quite a bit less readable.
Yeah, I'll just change my text editor because someone in the team wants to use this rule.
So convenient.
> A single `indent-region` in emacs and you are rejustified, no trouble.
Because when you refactor the function/class name, it's never just one region. So now you have to go back and indent all occurrences, maybe even over multiple files. Brilliant!
... the region is whatever you say it is:
(mark-whole-buffer)
(indent-region)
Or, most likely, something like: C-x h TABI don't think that's particularly onerous.
It's only a few lines of elisp to visit all the files in a tree and automatically format them. That said, it would probably be more sensible to modify whatever refactoring tool to be indentation aware, if it isn't already. Again, that's easy to do with elisp.
But I'm not clear what's being suggested in the article. Personally, I'd turn:
foo = long_function_name(var_one, var_two,
var_three, var_four)
into: foo = long_function_name(
var_one, var_two, var_three, var_four
)
or: foo = long_function_name(
var_one,
var_two,
var_three,
var_four,
)
depending on the actual length. (Or all on one line if short enough of course.)"Aligned with opening delimiter" basically just means "put all the code as close to our column limit as possible", which is nuts.
def very_long_function_name(arg_one, arg_two, arg_three, arg_four):
... def very_long_function_name(
arg_one,
arg_two,
arg_three,
arg_four
):
It's consistent and doesn't require spaces so it lets you use tabs to let the reader choose its indentation size. def very_long_function_name(
arg_one,
arg_two,
arg_three,
arg_four
):
pass
For data structures, I definitely prefer the bracket to be on it's own line, but for function definitions I don't, so I'm also a fan of: def very_long_function_name(
arg_one,
arg_two,
arg_three,
arg_four):
pass
def very_long_function_name(
arg_one, arg_two, arg_three, arg_four):
pass def very_long_function_name(
arg_one, arg_two, arg_three, arg_four):
pass
Please don't. It looks awful.`):` always either on the first (and only) line or the last line, which ensures it either over-runs the function body indention level, or falls short:
def a():
pass
def b(
):
pass def very_long_function_name(
arg_one,
arg_two,
arg_three,
arg_four
):
...
The nice thing here is that the close parenthesis separates the parameters from the function body, without having to do anything like double-indenting.What's interesting to me is to try to understand why people are attracted to the column-aligned style even when it has so many problems. I think it comes directly from being unwilling to put spaces inside the parentheses when it's a one-liner:
long_function_name(var_one, var_two, var_three, var_four)
If you find that line getting too long and want to break it into multiple lines, it's natural that the first thing you do is to turn spaces into newlines: long_function_name(var_one,
var_two,
var_three,
var_four)
Well that's ugly, so what can we do with it? A few people indent the arguments after the first one: long_function_name(var_one,
var_two,
var_three,
var_four)
That doesn't make much sense; why is the first argument not lined up with the rest? So the next natural thing to try is the column aligned style: long_function_name(var_one,
var_two,
var_three,
var_four)
And now you have the problems that brings; fiddly maintenance and excessive line lengths.But what if you cultivate a style of putting spaces inside the parens, like this:
long_function_name( var_one, var_two, var_three, var_four )
Now when you have to break it into multiple lines, the natural place to start is again to turn the spaces into newlines: long_function_name(
var_one,
var_two,
var_three,
var_four
)
and from here it's simple to add some indentation: long_function_name(
var_one,
var_two,
var_three,
var_four
)
What I haven't figured out is why so many programmers are opposed to putting spaces inside the parentheses. Not only does this lead to better practices when you switch back and forth between single line and multiline styles, but it's more logical too. In this example, the open paren "belongs" to the function call, not to the first argument. Why should the arguments get spaces between then, but the first argument is a special case, directly attached to the function name?In fact, PEP8, if you take it as gospel, forbids spaces inside the parentheses. But as is common with these things, it gives no reason or rationale for this. It's simply listed as a "pet peeve".
I've seen a few style guides where the authors realized it would be nice to have some whitespace between the function name and first argument, but just couldn't bring themselves to try putting the space inside the parentheses, so they put it outside:
long_function_name (var_one, var_two, var_three, var_four)
A lot of Unity C# code is written like this, because it's MonoDevelop's default style. It's not terrible when you see a simple example, but it gets pretty bad when there are nested functions: DoSomething (Foo (x), Bar (y))
The whitespace here has very little to do with the actual structure of the code. Contrast this with: DoSomething( Foo(x), Bar(y) )
Now the things that belong most closely together are visually connected, and spaces separate the things that are less connected. I didn't put spaces inside the parens for the inner functions, only the outer one, to help emphasize what is connected to what."""This line doesn't start at the start.
But this one does, and the following one ends at the start.
"""
"""\
This line starts at the start.
And so do the following ones.
"""What I'll amend is the rule about not having spaces around = in argument lists. It looks horrible and it induces some people at omitting spaces in assignments. I've never seen so many var=value in source code as in Python, since the time of PHP.
Double quotes are just so much easier to catch visually.
function_call(
arg1, arg2, arg3
)
def function_call(
arg1, arg2, arg3
):
pass):
My issue with this is that, in reality, everything will now be 100 chars.