A "Best of the Best Practices" (BOBP) guide to developing in Python.
A "Best of the Best Practices" (BOBP) guide to developing in Python.
Follow PEP 8, when sensible.
lower_case_with_underscores
CapWords
_single_leading_underscore(self, ...)
__double_leading_underscore(self, ...)
ALL_CAPS_WITH_UNDERSCORES
Avoid one-letter variables (esp. l
, O
, I
).
Exception: In very short blocks, when the meaning is clearly visible from the immediate context
Fine
for e in elements:
e.mutate()
Avoid redundant labeling.
Yes
import audio
core = audio.Core()
controller = audio.Controller()
No
import audio
core = audio.AudioCore()
controller = audio.AudioController()
Prefer "reverse notation".
Yes
elements = ...
elements_active = ...
elements_defunct = ...
No
elements = ...
active_elements = ...
defunct_elements ...
Avoid getter and setter methods.
Yes
person.age = 42
No
person.set_age(42)
Use 4 spaces--never tabs. Enough said.
Import entire modules instead of individual symbols within a module. For example, for a top-level module canteen
that has a file canteen/sessions.py
,
Yes
import canteen
import canteen.sessions
from canteen import sessions
No
from canteen import get_user # Symbol from canteen/__init__.py
from canteen.sessions import get_session # Symbol from canteen/sessions.py
Exception: For third-party code where documentation explicitly says to import individual symbols.
Rationale: Avoids circular imports. See here.
Put all imports at the top of the page with three sections, each separated by a blank line, in this order:
Rationale: Makes it clear where each module is coming from.
Follow PEP 257's docstring guidelines. reStructured Text and Sphinx can help to enforce these standards.
Use one-line docstrings for obvious functions.
"""Return the pathname of ``foo``."""
Multiline docstrings should include
None
is returned"""Train a model to classify Foos and Bars.
Usage::
>>> import klassify
>>> data = [("green", "foo"), ("orange", "bar")]
>>> classifier = klassify.train(data)
:param train_data: A list of tuples of the form ``(color, label)``.
:rtype: A :class:`Classifier <Classifier>`
"""
Notes
__init__
methods in the docstring for the class.class Person(object):
"""A simple representation of a human being.
:param name: A string, the person's name.
:param age: An int, the person's age.
"""
def __init__(self, name, age):
self.name = name
self.age = age
Use them sparingly. Prefer code readability to writing a lot of comments. Often, small methods are more effective than comments.
No
# If the sign is a stop sign
if sign.color == 'red' and sign.sides == 8:
stop()
Yes
def is_stop_sign(sign):
return sign.color == 'red' and sign.sides == 8
if is_stop_sign(sign):
stop()
When you do write comments, remember: "Strunk and White apply." - PEP 8
Don't stress over it. 80-100 characters is fine.
Use parentheses for line continuations.
wiki = (
"The Colt Python is a .357 Magnum caliber revolver formerly manufactured "
"by Colt's Manufacturing Company of Hartford, Connecticut. It is sometimes "
'referred to as a "Combat Magnum". It was first introduced in 1955, the '
"same year as Smith & Wesson's M29 .44 Magnum."
)
Strive for 100% code coverage, but don't get obsess over the coverage score.
assert False, "TODO: finish me"
.import unittest
import factories
class PersonTest(unittest.TestCase):
def setUp(self):
self.person = factories.PersonFactory()
def test_has_age_in_dog_years(self):
self.assertEqual(self.person.dog_years, self.person.age / 7)
Functional tests are higher level tests that are closer to how an end-user would interact with your application. They are typically used for web and GUI applications.
import unittest
class TestAUser(unittest.TestCase):
def test_can_write_a_blog_post(self):
# Goes to the her dashboard
...
# Clicks "New Post"
...
# Fills out the post form
...
# Clicks "Submit"
...
# Can see the new post
...
Notice how the testcase and test method read together like "Test A User can write a blog post".