mirror of
https://github.com/kennethreitz/python-guide.git
synced 2026-06-05 14:50:19 +00:00
361 lines
9.1 KiB
ReStructuredText
361 lines
9.1 KiB
ReStructuredText
Code Style
|
||
==========
|
||
|
||
|
||
Idioms
|
||
------
|
||
|
||
Idiomatic Python code is often referred to as being *Pythonic*.
|
||
|
||
.. _unpacking-ref:
|
||
|
||
Unpacking
|
||
~~~~~~~~~
|
||
|
||
If you know the length of a list or tuple, you can assign names to its
|
||
elements with unpacking:
|
||
|
||
.. code-block:: python
|
||
|
||
for index, item in enumerate(some_list):
|
||
# do something with index and item
|
||
|
||
You can use this to swap variables, as well:
|
||
|
||
.. code-block:: python
|
||
|
||
a, b = b, a
|
||
|
||
Create an ignored variable
|
||
~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||
|
||
If you need to assign something (for instance, in :ref:`unpacking-ref`) but
|
||
will not need that variable, use ``_``:
|
||
|
||
.. code-block:: python
|
||
|
||
filename = 'foobar.txt'
|
||
basename, _, ext = filename.rpartition()
|
||
|
||
.. note::
|
||
|
||
"``_``" is commonly used as an alias for the :func:`~gettext.gettext`
|
||
function. If your application uses (or may someday use) :mod:`gettext`,
|
||
you may want to avoid using ``_`` for ignored variables, as you may
|
||
accidentally shadow :func:`~gettext.gettext`.
|
||
|
||
Create a length-N list of the same thing
|
||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||
|
||
Use the Python list ``*`` operator:
|
||
|
||
.. code-block:: python
|
||
|
||
four_nones = [None] * 4
|
||
|
||
Create a length-N list of lists
|
||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||
|
||
Because lists are mutable, the ``*`` operator (as above) will create a list
|
||
of N references to the `same` list, which is not likely what you want.
|
||
Instead, use a list comprehension:
|
||
|
||
.. code-block:: python
|
||
|
||
four_lists = [[] for _ in xrange(4)]
|
||
|
||
|
||
|
||
Zen of Python
|
||
-------------
|
||
|
||
Also known as PEP 20, the guiding principles for Python's design.
|
||
|
||
::
|
||
|
||
>>> import this
|
||
The Zen of Python, by Tim Peters
|
||
|
||
Beautiful is better than ugly.
|
||
Explicit is better than implicit.
|
||
Simple is better than complex.
|
||
Complex is better than complicated.
|
||
Flat is better than nested.
|
||
Sparse is better than dense.
|
||
Readability counts.
|
||
Special cases aren't special enough to break the rules.
|
||
Although practicality beats purity.
|
||
Errors should never pass silently.
|
||
Unless explicitly silenced.
|
||
In the face of ambiguity, refuse the temptation to guess.
|
||
There should be one-- and preferably only one --obvious way to do it.
|
||
Although that way may not be obvious at first unless you're Dutch.
|
||
Now is better than never.
|
||
Although never is often better than *right* now.
|
||
If the implementation is hard to explain, it's a bad idea.
|
||
If the implementation is easy to explain, it may be a good idea.
|
||
Namespaces are one honking great idea -- let's do more of those!
|
||
|
||
For some examples of good Python style, see `this Stack Overflow question
|
||
<http://stackoverflow.com/questions/228181/the-zen-of-python>`_ or `these
|
||
slides from a Python user group
|
||
<http://artifex.org/~hblanks/talks/2011/pep20_by_example.pdf>`_.
|
||
|
||
PEP 8
|
||
-----
|
||
|
||
PEP 8 is the de-facto code style guide for Python.
|
||
|
||
`PEP 8 <http://www.python.org/dev/peps/pep-0008/>`_
|
||
|
||
Conforming your Python code to PEP 8 is generally a good idea and helps make
|
||
code more consistent when working on projects with other developers. There
|
||
exists a command-line program, `pep8 <https://github.com/jcrocholl/pep8>`_,
|
||
that can check your code for conformance. Install it by running the following
|
||
command in your Terminal:
|
||
|
||
::
|
||
|
||
$ pip install pep8
|
||
|
||
|
||
Then run it on a file or series of files to get a report of any violations.
|
||
|
||
::
|
||
|
||
$ pep8 optparse.py
|
||
optparse.py:69:11: E401 multiple imports on one line
|
||
optparse.py:77:1: E302 expected 2 blank lines, found 1
|
||
optparse.py:88:5: E301 expected 1 blank line, found 0
|
||
optparse.py:222:34: W602 deprecated form of raising exception
|
||
optparse.py:347:31: E211 whitespace before '('
|
||
optparse.py:357:17: E201 whitespace after '{'
|
||
optparse.py:472:29: E221 multiple spaces before operator
|
||
optparse.py:544:21: W601 .has_key() is deprecated, use 'in'
|
||
|
||
Conventions
|
||
:::::::::::
|
||
|
||
Here are some conventions you should follow to make your code easier to read.
|
||
|
||
Check if variable equals a constant
|
||
-----------------------------------
|
||
|
||
You don't need to explicitly compare a value to True, or None, or 0 - you can
|
||
just add it to the if statement. See `Truth Value Testing
|
||
<http://docs.python.org/library/stdtypes.html#truth-value-testing>`_ for a
|
||
list of what is considered false.
|
||
|
||
**Bad**:
|
||
|
||
.. code-block:: python
|
||
|
||
if attr == True:
|
||
print 'True!'
|
||
|
||
if attr == None:
|
||
print 'attr is None!'
|
||
|
||
**Good**:
|
||
|
||
.. code-block:: python
|
||
|
||
# Just check the value
|
||
if attr:
|
||
print 'attr is truthy!'
|
||
|
||
# or check for the opposite
|
||
if not attr:
|
||
print 'attr is falsey!'
|
||
|
||
# or, since None is considered false, explicity check for it
|
||
if attr is None:
|
||
print 'attr is None!'
|
||
|
||
Access a Dictionary Element
|
||
---------------------------
|
||
|
||
Don't use the ``has_key`` function. Instead use ``x in d`` syntax, or pass
|
||
a default argument to ``get``.
|
||
|
||
**Bad**:
|
||
|
||
.. code-block:: python
|
||
|
||
d = {'hello': 'world'}
|
||
if d.has_key('hello'):
|
||
print d['hello'] # prints 'world'
|
||
else:
|
||
print 'default_value'
|
||
|
||
**Good**:
|
||
|
||
.. code-block:: python
|
||
|
||
d = {'hello': 'world'}
|
||
|
||
print d.get('hello', 'default_value') # prints 'world'
|
||
print d.get('thingy', 'default_value') # prints 'default_value'
|
||
|
||
# Or:
|
||
if 'hello' in d:
|
||
print d['hello']
|
||
|
||
Short Ways to Manipulate Lists
|
||
------------------------------
|
||
|
||
`List comprehensions
|
||
<http://docs.python.org/tutorial/datastructures.html#list-comprehensions>`_
|
||
provide a powerful, concise way to work with lists. Also, the `map
|
||
<http://docs.python.org/library/functions.html#map>`_ and `filter
|
||
<http://docs.python.org/library/functions.html#filter>`_ functions can perform
|
||
operations on lists using a different concise syntax.
|
||
|
||
**Bad**:
|
||
|
||
.. code-block:: python
|
||
|
||
# Filter elements greater than 4
|
||
a = [3, 4, 5]
|
||
b = []
|
||
for i in a:
|
||
if i > 4:
|
||
b.append(i)
|
||
|
||
**Good**:
|
||
|
||
.. code-block:: python
|
||
|
||
b = [i for i in a if i > 4]
|
||
b = filter(lambda x: x > 4, a)
|
||
|
||
**Bad**:
|
||
|
||
.. code-block:: python
|
||
|
||
# Add three to all list members.
|
||
a = [3, 4, 5]
|
||
count = 0
|
||
for i in a:
|
||
a[count] = i + 3
|
||
count = count + 1
|
||
|
||
**Good**:
|
||
|
||
.. code-block:: python
|
||
|
||
a = [3, 4, 5]
|
||
a = [i + 3 for i in a]
|
||
# Or:
|
||
a = map(lambda i: i + 3, a)
|
||
|
||
Use `enumerate <http://docs.python.org/library/functions.html#enumerate>`_ to
|
||
keep a count of your place in the list.
|
||
|
||
.. code-block:: python
|
||
|
||
for i, item in enumerate(a):
|
||
print i + ", " + item
|
||
# prints
|
||
# 0, 3
|
||
# 1, 4
|
||
# 2, 5
|
||
|
||
The ``enumerate`` function has better readability than handling a counter
|
||
manually. Moreover,
|
||
it is better optimized for iterators.
|
||
|
||
Read From a File
|
||
----------------
|
||
|
||
Use the ``with open`` syntax to read from files. This will automatically close
|
||
files for you.
|
||
|
||
**Bad**:
|
||
|
||
.. code-block:: python
|
||
|
||
f = open('file.txt')
|
||
a = f.read()
|
||
print a
|
||
f.close()
|
||
|
||
**Good**:
|
||
|
||
.. code-block:: python
|
||
|
||
with open('file.txt') as f:
|
||
for line in f:
|
||
print line
|
||
|
||
The ``with`` statement is better because it will ensure you always close the
|
||
file, even if an exception is raised.
|
||
|
||
Returning Multiple Values from a Function
|
||
-----------------------------------------
|
||
|
||
Python supports returning multiple values from a function as a comma-separated
|
||
list, so you don't have to create an object or dictionary and pack multiple
|
||
values in before you return
|
||
|
||
**Bad**:
|
||
|
||
.. code-block:: python
|
||
|
||
def math_func(a):
|
||
return {'square': a ** 2, 'cube': a ** 3}
|
||
|
||
d = math_func(3)
|
||
s = d['square']
|
||
c = d['cube']
|
||
|
||
**Good**:
|
||
|
||
.. code-block:: python
|
||
|
||
def math_func(a):
|
||
return a ** 2, a ** 3
|
||
|
||
square, cube = math_func(3)
|
||
|
||
Line Continuations
|
||
~~~~~~~~~~~~~~~~~~
|
||
|
||
When a logical line of code is longer than the accepted limit, you need to
|
||
split it over multiple physical lines. Python interpreter will join consecutive
|
||
lines if the last character of the line is a backslash. This is helpful
|
||
sometime but is preferably avoided, because of its fragility: a white space
|
||
added to the end of the line, after the backslash, will break the code and may
|
||
have unexpected results.
|
||
|
||
A prefered solution is to use parenthesis around your elements. Left with an
|
||
unclosed parenthesis on an end-of-line the Python interpreter will join the
|
||
next line until the parenthesis is closed. The same behavior holds for curly
|
||
and square braces.
|
||
|
||
**Bad**:
|
||
|
||
.. code-block:: python
|
||
|
||
my_very_big_string = """For a long time I used to go to bed early. Sometimes, \
|
||
when I had put out my candle, my eyes would close so quickly that I had not even \
|
||
time to say “I’m going to sleep.”"""
|
||
|
||
from some.deep.module.inside.a.module import a_nice_function, another_nice_function, \
|
||
yet_another_nice_functio
|
||
|
||
**Good**:
|
||
|
||
.. code-block:: python
|
||
|
||
my_very_big_string = ("For a long time I used to go to bed early. Sometimes, "
|
||
"when I had put out my candle, my eyes would close so quickly that I had not even "
|
||
time to say “I’m going to sleep.”")
|
||
|
||
from some.deep.module.inside.a.module import (a_nice_function, another_nice_function,
|
||
yet_another_nice_functio)
|
||
|
||
However, more often than not having to split long logical line is a sign that
|
||
you are trying to do too many things at the same time, which may hinder
|
||
readability.
|