Python style guide

From brainsik
Jump to navigation Jump to search

This style guide descends from the Python documentation and work done at Mosuki, Devsuki, and Sycle.

For anything not covered in this document, follow PEP 8, PEP 257, and Idioms and Anti-Idioms in Python.

Encoding

  • All files should be written using the UTF-8 encoding; set your editor accordingly.
  • All files should have the encoding specified at the very top of the file (underneath the #! line if it exists):
# encoding: utf-8

Arrangement

Modules should be arranged like:

  1. imports
  2. configuration variables
  3. functions
  4. classes

Imports should be arranged so that "import X" is followed by "from X import Y" in blocks ordered by:

  1. standard library
  2. external packages
  3. local packages
  4. current package


Methods should be arranged like:

  1. __init__
  2. other __double_underscored__ methods that override Python built-in functionality
  3. _protected methods
  4. public methods

Empty lines

  1. Two empty lines separate top level functions and classes.
  2. One empty lines separate methods.
  3. One empty line may separate conceptually different chunks of code in the same namespace, like control flow blocks (if/elif/else/try/except/for/while/finally/with).

Identifiers

  • no abbrs. (abbreviations)
    • It's ok to use a clear abbreviation for an identifier that would otherwise collide with a Python keyword or builtin: buf for buffer, cls for class, etc.
  • NA (no acronyms)
  • no wordsruntogether
  • no STuDLyCaPS
  • no CamelCase, mixedCase, mixed_Case, or Title_Case
    • CapitalizeEachWord in class names only
  • Do not use negated or negative terminology
    • use send_claim=True instead of do_not_send_claim=False
    • use escape_output=True instead of disable_output_escaping=False
  • Avoid plurals when a singular, or similar singulars, are used in the same or similar objects, classes, modules, scopes, or contexts.
  • Try to find a good word that describes an entire collection, and fall back to plurals if you can't.
    • Examples: team instead of players, staff instead of employees, whitelist instead of allowed_items, story instead of paragraphs, menu instead of entrees
  • Don't use int, str or other scalar type names as sub-parts of identifiers.
  • separate words with '_' always
  • be as descriptive as possible in identifiers
  • the length of an identifier should be inversely proportional to its scope:
    • class attributes, methods, and values passed between functions should be descriptive and as long as necessary
    • short identifiers are only ok inside functions and methods
    • extremely short identifiers are only ok as throwaway variables, iteration indexes, etc.
    • long identifiers are ok and almost always good. If your text editor cannot autocomplete long identifiers for you, get a new text editor. Optimize for comprehension, not keystrokes.
  • try to stick to the same identifiers for the same things
    • use the same identifiers in function/method arguments in their definition and where they are called
    • use the same identifiers for similar/overridden method's names and scopes in derived classes
    • &c.
  • function, method, and executable names should be verb-like
  • object, variable, attribute and property names should be noun-like:
    • GOOD: foo_bar = foo_to_bar(foo, bar)
    • BAD: foo_to_bar = foo_bar(foo, bar)

String literals

  • Use single quotes around keys and values that are symbol-like, from a fixed or constrained set
  • Use double quotes around free-form text
  • Ok to use the other kind of quote when you need to include a quote in a string

Comments

  • Comment out an unused line of code with a single #
  • Comment out English explanations with # (octothorp followed by a space) to distinguish English from Python
  • A comment on the same line as code should have two spaces preceding the #
  • Don't be shy about deleting unused code rather than commenting it out. Version control is for remembering old code. Comments are not for remembering old code.

Labels

Comment labels make it easy to ack or grep for known issues. There's also a TextMate bundle for them called "TODO".

  • Label known problems to fix with # BUG: followed by an explanation
  • Label known deficiencies to implement with # TODO: followed by an exaplanation
  • Hacks should always be avoided (this is technical debt) but sometimes happen. Label your sin with # HACK: or BUG: HACK: followed by an explanation of the Right Way to do things.

A less well defined tag we use is # NOTE: . These typically indicate comments of an important nature: pitfalls, important details, etc.

Example

import os
import sys
from functools import partial

import spam

from mypackage.othermodule import OtherObject


def be_fruitful_and(a, b, do_what='multiply'):
  """Fruitly go and be."""

  if do_what == 'multiply':
    print "multiplying %d and %d" % (a, b)
    return a*b
  elif do_what == 'divide':
    # Man, this sure is fun
    print "dividing %d and %d because it's fun" % (a, b)
    return a*b
  # BUG: need to support addition and subtraction
  else:
    #raise Exception("Sorry, I don't know how to %s" % do_what)
    print "Sorry, I don't know how to %s" % do_what


class Foo(spam):
  """Provide a Foo interface for frobbing spam."""

  def __init__(self):
    """Initialize stuff."""
    y = 7
    x = 12
    self.x_times_y = be_fruitful_and(x, y)

  def bar(self):
    """Barify the foo."""
    z = self.x_times_y
    self.x_times_y = 0
    return z


class Bar(Foo):
  """Extend :class:`Foo` with tasty Barness."""

  def bar(self):
    """Barify the bar.
    
    Barification of the bar allows for further frobbing of Fooified spam.
    """
    z = Foo.bar(self)
    return z + 1

  def something_else(self, another_value):
    """Do that other thing."""
    yet_another_value = another_value % self.x_times_y
    return be_fruitful_and(another_value, self.x_times_y)