tags:

views:

182

answers:

7

The title says most of it really :) Over the years, the more Python I write, the more I find myself agreeing with most of the guidelines, some though I consistently and intentionally break for my own reasons.

I'd be curious to know what in PEP 8 (or other PEPs too maybe) people religiously stick to and why, and what people find inconvenient or inadequate.

In my case (and at work in general), there's only a handful of things we deviate from: Underscore separated lowercase names, I can see the point of it, as it will unfailingly be consistent, but we tend to use lowerCamelCase, even if it will occasionally introduce some inconsistencies (such as partially or mis-capitalized acronyms and following words, which are often down to spur-of-the-moment calls). Mostly because the near totality of the APIs we routinely use use camelCase (some upper, some lower), and because for some reason I find it easier to read, and tend to reserve underscores as separation tokens or prescribed mangling/obscuring.

I still can't get myself to space things out the way the pep prescribes inside objects. new and init I tend to leave right under the class with no blank lines as I always want to read them right there with the class name and args, methods that contribute to the same scope of functionality in the class (say init, get and set of the same attrib or set of attribs) I only singe space apart, and I like three spaces between classes, and two between methods I wouldn't mentally aggregate in the map of that object.

This is, again, purely for the visual impact and readability of the code. I find that very compact contents inside flow control and this kind of spacing between methods and objects consistently leads my eye exactly where I want it to go on re-readings months after the code had been parked. It also responds well to folding in my editors of choice.

Some things instead I stick to, that drive me nuts when I read otherwise written, is tabs instead of spaces (especially when some in-app editors we use don't really have tab replacement functionalities, contributing considerably to pollution in the code base at prototyping stage).

Order of things such as imports, and what imports, globals etc. It really throws me off on files that have large amounts of imports when those are mixed up or out of order.

Whitespaces in statements, especially when people use tabs AND try to align assignment ops across lines with different length in var names (and there seems to be no way to persuade those who do it that an excel looking piece of code is NOT neater ;) ).

And spacing within a control block, particularly when I see apparently random spacing within the same flow control block, and then similar amounts of spacing used within the object for methods. I'm compelled to edit those before I can even start reading the damn thing.

So, those are mine, and the reasoning behind my "violations" of the PEP (some shared, some frowned upon by colleagues). I'd be very curious to read what other Pythonistas do and don't do in those regards.

+1  A: 

When I'm writing tiny scripts I often just just use two spaces.

I always the same pattern for docstrings:

def function():
    """
    Even if it's a single line.
    """
Tim McNamara
Two-space indentation is very hard to read in any language. I'm not a stickler for four-space indents--I often use eight, largely out of long habit--but reading anything less is very uncomfortable.
Glenn Maynard
Java seems to love 2 spaces, probably because you will always have to indent two levels before you actually start writing any code.
Nick T
@Nick: For all the objective reasons I dislike Java, I have a feeling I'd *subjectivally* hate it a lot less if it wasn't like that.
Glenn Maynard
Java requires 2 space indentation to be readable because it's an overly verbose language and anything less causes you to run out of horizontal space too soon
Lie Ryan
I find it surprising that this has been down-voted.. the question isn't asking for recommendations. It's just asking for how people behave. The only reason to vote downwards on this answer would be if you knew that I was lying.
Tim McNamara
@Tim: +1 because I believe you.
intuited
ha thanks @intuited
Tim McNamara
+2  A: 

I always use 4 spaces, I try to use maximum of 79 chars per line, not possible sometime. I also used imports like "import sys, os" in the past. In general I try to stick to pop 8.

Edit: also use:

def foobar():
    """
    foobar
    """

for documentation

kelvan
+1  A: 

Hi, I use pylint, http://pypi.python.org/pypi/pylint, it is an excellent tool to try to keep your code clean and readable for you and other developers accessing your code.

I does not cover all topics you said, though, but it is very useful.

You can have reports like this one:

carlos@debian:~/src/fcl/cltools$ pylint numbertoletters.py
No config file found, using default configuration
************* Module numbertoletters
C:  1: Missing docstring
C: 56:es_numero: Missing docstring
C: 56:es_numero: Invalid name "s" (should match [a-z_][a-z0-9_]{2,30}$)
C: 56:es_numero: Invalid name "s" (should match [a-z_][a-z0-9_]{2,30}$)
C: 69:convertnumbertoletters: Empty docstring
C: 90:convertnumbertoletters: Operator not preceded by a space
    numero='%(numero)09d' % {'numero' : int(parte_entera)}
          ^
C: 92:convertnumbertoletters: Comma not followed by a space
    for i in [0,3,6]:
               ^^

W: 69:convertnumbertoletters: Unused argument 'languaje'
C:108:unidades: Empty docstring
C:108:unidades: Invalid name "x" (should match [a-z_][a-z0-9_]{2,30}$)
C:108:unidades: Invalid name "x" (should match [a-z_][a-z0-9_]{2,30}$)
C:112:unidades: Invalid name "u" (should match [a-z_][a-z0-9_]{2,30}$)
C:118:teens: Empty docstring
C:118:teens: Invalid name "x" (should match [a-z_][a-z0-9_]{2,30}$)
C:118:teens: Invalid name "x" (should match [a-z_][a-z0-9_]{2,30}$)
C:122:teens: Invalid name "t" (should match [a-z_][a-z0-9_]{2,30}$)
C:127:tens: Empty docstring
C:127:tens: Invalid name "x" (should match [a-z_][a-z0-9_]{2,30}$)
C:127:tens: Invalid name "x" (should match [a-z_][a-z0-9_]{2,30}$)
C:131:tens: Invalid name "t" (should match [a-z_][a-z0-9_]{2,30}$)
C:137:tercia: Empty docstring
C:141:tercia: Operator not preceded by a space
    numero='%(numero)03d' % {'numero' : int(num)}
          ^
C:143:tercia: Invalid name "a" (should match [a-z_][a-z0-9_]{2,30}$)
C:144:tercia: Invalid name "b" (should match [a-z_][a-z0-9_]{2,30}$)
C:145:tercia: Invalid name "c" (should match [a-z_][a-z0-9_]{2,30}$)
C:163:tercia: Operator not followed by a space
                resultado ='veinti '+unidades(c)
                          ^
C:165:tercia: Operator not followed by a space
        elif b >=3 and b <= 9:
               ^^
C:178:tercia: Operator not followed by a space
                resultado ='ciento '+unidades(c)
                          ^
C:192:tercia: Operator not followed by a space
                resultado ='ciento veinti '+unidades(c)
                          ^
C:204:tercia: Operator not preceded by a space
            prefix='quinientos '
                  ^
C:206:tercia: Operator not preceded by a space
            prefix='setecientos '
                  ^
C:208:tercia: Operator not preceded by a space
            prefix='novecientos '
                  ^
C:210:tercia: Operator not preceded by a space
            prefix=unidades(a)+'cientos '
                  ^
R:137:tercia: Too many return statements (23/6)
R:137:tercia: Too many branches (41/12)
R:137:tercia: Too many statements (73/50)


Report
======
141 statements analysed.

Raw metrics
-----------

+----------+-------+------+---------+-----------+
|type      |number |%     |previous |difference |
+==========+=======+======+=========+===========+
|code      |144    |68.25 |NC       |NC         |
+----------+-------+------+---------+-----------+
|docstring |5      |2.37  |NC       |NC         |
+----------+-------+------+---------+-----------+
|comment   |57     |27.01 |NC       |NC         |
+----------+-------+------+---------+-----------+
|empty     |5      |2.37  |NC       |NC         |
+----------+-------+------+---------+-----------+



Statistics by type
------------------

+---------+-------+-----------+-----------+------------+---------+
|type     |number |old number |difference |%documented |%badname |
+=========+=======+===========+===========+============+=========+
|module   |1      |NC         |NC         |0.00        |0.00     |
+---------+-------+-----------+-----------+------------+---------+
|class    |0      |NC         |NC         |0           |0        |
+---------+-------+-----------+-----------+------------+---------+
|method   |0      |NC         |NC         |0           |0        |
+---------+-------+-----------+-----------+------------+---------+
|function |6      |NC         |NC         |0.00        |0.00     |
+---------+-------+-----------+-----------+------------+---------+



Duplication
-----------

+-------------------------+------+---------+-----------+
|                         |now   |previous |difference |
+=========================+======+=========+===========+
|nb duplicated lines      |0     |NC       |NC         |
+-------------------------+------+---------+-----------+
|percent duplicated lines |0.000 |NC       |NC         |
+-------------------------+------+---------+-----------+



Messages by category
--------------------

+-----------+-------+---------+-----------+
|type       |number |previous |difference |
+===========+=======+=========+===========+
|convention |32     |NC       |NC         |
+-----------+-------+---------+-----------+
|refactor   |3      |NC       |NC         |
+-----------+-------+---------+-----------+
|warning    |1      |NC       |NC         |
+-----------+-------+---------+-----------+
|error      |0      |NC       |NC         |
+-----------+-------+---------+-----------+



Messages
--------

+-----------+------------+
|message id |occurrences |
+===========+============+
|C0103      |14          |
+-----------+------------+
|C0322      |6           |
+-----------+------------+
|C0112      |5           |
+-----------+------------+
|C0323      |4           |
+-----------+------------+
|C0111      |2           |
+-----------+------------+
|W0613      |1           |
+-----------+------------+
|R0915      |1           |
+-----------+------------+
|R0912      |1           |
+-----------+------------+
|R0911      |1           |
+-----------+------------+
|C0324      |1           |
+-----------+------------+



Global evaluation
-----------------
Your code has been rated at 7.45/10

I hope it helps.

I highly recommend the use of pylint to rate your code, and keep a standard way of programming, specially in a community of developers. =)

I hope it helps.

Carlos Balderas
Personally I do use pylint and like it. Mostly I was curious about other programmers personal "amendments" to PEP8, and why they feel they need to bend or ignore a particular guideline :)
ThE_JacO
Oh, ok, I did not get the point, sorry. =)
Carlos Balderas
+1  A: 

The "79 characters per line" part is nonsense. Their very own example shows how unreadable code becomes when doing this:

class Rectangle(Blob):

    def __init__(self, width, height,
                 color='black', emphasis=None, highlight=0):
        if width == 0 and height == 0 and \
           color == 'red' and emphasis == 'strong' or \
           highlight > 100:
            raise ValueError("sorry, you lose")
        if width == 0 and height == 0 and (color == 'red' or
                                           emphasis is None):
            raise ValueError("I don't think so -- values are %s, %s" %
                             (width, height))
        Blob.__init__(self, width, height,
                      color, emphasis, highlight)

It's like try-
ing to read
a news arti-
cle written
like this.

80-column terminals havn't been a serious development environment for over a decade. When I do need to edit from a crippled 80x25 environment in a pinch, editor wrapping is a minor inconvenience; I'm not going to maim my code during normal development just to avoid that.

120 column wrapping is perfectly sensible for modern development, and I have no problem with 140. This guideline is obsolete and following it results in ugly, hard-to-read code.

Glenn Maynard
79 characters per line lets one fit two pages of code onto a 1680px wide screen fairly easily. That code could also be formatted much better; it's something of a strawman against 79-character lines.
Nick T
Agreed, though I always try to wrap my documentation and comments at 80 characters.
Soviut
Oh, and you bring up news articles; there's a fairly basic reason that most newspapers will have columns about 2 inches wide: readability. Print is dead though, so I guess any concepts they've developed over the past centuries will as well.
Nick T
@Nick: I'm not going to massacre my code to accomodate your weird windowing arrangements. This code is copied *directly out of the PEP-8 section on wrapping*, so it's pointedly absurd to call it a "strawman".
Glenn Maynard
I was initially really opposed to the 80-character thing, but I find that if you wrap conditional sections like the one in this example in a set of parentheses, and use lisp-style indentation for it, it works out pretty well. If that's still not possible, I take it as a sign that I'm doing too much in one line, and create an intermediate variable assignment or function to handle part of the complexity. I actually forgot that it was possible to escape newlines with backlashes: I never do that.
intuited
if you add blank lines after wrapped lines, the code looks better. however, i essentially agree with you.
mykhal
+1 for 120 width. When I'm coding on a 27" iMac, I find even up to 180 columns to be fine, although I usually stick to 120.
Nick Presta
Putting two code windows side-by-side is weird?
Nick T
Nick T: I agree! I usually have multiple vertically-split viewports open (I use Vim). In addition, typically numerous other windows are open (e.g., several terminals, a browser, man/help pages). Thus, my individual buffers usually end up having viewports of 100-120 cols wide, even if I have huge monitor(s). Most other coders I've worked with do the same, and so your windowing logic is not only NOT "weird", it makes pretty good sense. At the end of the day, however, I do not ask anyone to change their practices to accommodate me, so nobody needs to resort to murder, of code or otherwise.
Jeet
@Jeet: `vim` has pretty decent line-wrapping facilities (though not as good as e.g. `kate`, which aligns the indent of the wrapped lines) so you're not totally screwed over by the occasional long line.
intuited
+2  A: 

Multi-line conditionals etc.: PEP-8 explicitly says to break after a binary operator instead of before it. I'm afraid that I cannot see the appeal of that. It makes a lot more sense to me to break before the conditional, so that in wrapped/continued lines, each sub-line begins with the conditional:

if (condition1 \
        or condition2 \
        or condition3):
    do_something()

As can be seen, I also like to add an extra indent for the sublines, so that they are visually offset from the block below. PEP-8 does not say anything explicit about this (does it?), but the examples have the sub-lines lining up with the opening parentheses.

Jeet
You don't actually need the end-of-line backslashes here: a line can't end within a set of parentheses, so they continue anyway. I agree with you BTW, it seems clearer to put the conditional where it's obvious at a glance.
intuited
re: backslashes -- I know ... but for some reason I tend to add them!
Jeet
Continuation backslashes in Python make me feel like I'm reading a big C preprocessor macro. Nobody should have to feel that way...
Glenn Maynard
A: 

PEP 8 says:

Yes:

x = 1
y = 2
long_variable = 3

No:

x             = 1
y             = 2
long_variable = 3

i usually follow it, but i sometimes use another variant, for the sake of better readability:

x =             1
y =             2
long_variable = 3
mykhal
I might agree with this if you have a long list of related assignments; for example, if you're copying a list of enum values from a C header. For small quantities, as is usually the case for local variables, I'd leave out the alignment, though.
Glenn Maynard
"better readability"? Disputable. It's just **your** preference. Some of us don't find it readable at all. COBOL programmers do it a lot and it doesn't help there, either.
S.Lott
+5  A: 

I don't agree with this:

- Imports should usually be on separate lines, e.g.:

    Yes: import os
         import sys

    No:  import sys, os

I always write simple imports together. I don't see any advantage to writing them all on separate lines: all it does is add bloat to the top of each source file, and turn something concise and easy to type into something that's borderline boilerplate, eg. something that's so verbose it starts to be tempting to copy and paste from other files.

This is instantly readable and understandable:

import sys, os, time, gc, inspect, math, doctest

It's short, easy to skim, and easy to add to. I do use multiple import statements if there are too many on one line, of course, or if I need a from import.

I also do generally keep standard library imports separate from imports of my own modules and other libraries, which agrees with the concept of grouping PEP8 recommends.

Glenn Maynard