mirror of
https://github.com/kennethreitz/python-guide.git
synced 2026-06-05 23:00:18 +00:00
Merge branch 'master' into standard-american-english
This commit is contained in:
@@ -25,7 +25,7 @@ information. This file is the main entry point for readers of the code.
|
||||
|
||||
An :file:`INSTALL` file is less necessary with Python. The installation
|
||||
instructions are often reduced to one command, such as ``pip install
|
||||
module`` or ``python setup.py install`` and added to the :file:`README`
|
||||
module`` or ``python setup.py install``, and added to the :file:`README`
|
||||
file.
|
||||
|
||||
A :file:`LICENSE` file should *always* be present and specify the license
|
||||
@@ -75,7 +75,7 @@ your source repository so that rebuilding your documentation will
|
||||
happen automatically.
|
||||
|
||||
When run, Sphinx_ will import your code and using Python's introspection
|
||||
features it will extract all function, method and class signatures. It will
|
||||
features it will extract all function, method, and class signatures. It will
|
||||
also extract the accompanying docstrings, and compile it all into well
|
||||
structured and easily readable documentation for your project.
|
||||
|
||||
@@ -215,7 +215,7 @@ more information about a function, what it does, any exceptions it may raise,
|
||||
what it returns, or relevant details about the parameters.
|
||||
|
||||
For more detailed documentation of code a popular style is the one used for the
|
||||
Numpy project, often called `Numpy style`_ docstrings. While it can take up more
|
||||
NumPy project, often called `NumPy style`_ docstrings. While it can take up more
|
||||
lines than the previous example, it allows the developer to include a lot
|
||||
more information about a method, function, or class. ::
|
||||
|
||||
@@ -245,8 +245,8 @@ docstrings, making it easy to incorporate NumPy style docstrings into your
|
||||
project.
|
||||
|
||||
At the end of the day, it doesn't really matter what style is used for writing
|
||||
docstrings, their purpose is to serve as documentation for anyone who may need
|
||||
to read or make changes to your code. As long as it is correct, understandable
|
||||
docstrings; their purpose is to serve as documentation for anyone who may need
|
||||
to read or make changes to your code. As long as it is correct, understandable,
|
||||
and gets the relevant points across then it has done the job it was designed to
|
||||
do.
|
||||
|
||||
|
||||
@@ -205,7 +205,7 @@ will automatically write a bytecode version of that file to disk, e.g.
|
||||
|
||||
These ``.pyc`` files should not be checked into your source code repositories.
|
||||
|
||||
Theoretically, this behavior is on by default, for performance reasons.
|
||||
Theoretically, this behavior is on by default for performance reasons.
|
||||
Without these bytecode files present, Python would re-generate the bytecode
|
||||
every time the file is loaded.
|
||||
|
||||
|
||||
@@ -19,18 +19,18 @@ In general, these licenses tend to fall into one of two categories:
|
||||
|
||||
1. licenses that focus more on the user's freedom to do with the
|
||||
software as they please (these are the more permissive open
|
||||
source licenses such as the MIT, BSD, & Apache).
|
||||
source licenses such as the MIT, BSD, and Apache)
|
||||
|
||||
2. licenses that focus more on making sure that the code itself —
|
||||
including any changes made to it and distributed along with it —
|
||||
always remains free (these are the less permissive free software
|
||||
licenses such as the GPL and LGPL).
|
||||
licenses such as the GPL and LGPL)
|
||||
|
||||
The latter are less permissive in the sense that they don't permit
|
||||
someone to add code to the software and distribute it without also
|
||||
including the source code for their changes.
|
||||
|
||||
To help you choose one for your project, there's a `license chooser <http://choosealicense.com/>`_,
|
||||
To help you choose one for your project, there's a `license chooser <http://choosealicense.com/>`_;
|
||||
**use it**.
|
||||
|
||||
**More Permissive**
|
||||
|
||||
@@ -58,7 +58,7 @@ hierarchy of loggers using dot notation, so using ``__name__`` ensures
|
||||
no name collisions.
|
||||
|
||||
Here is an example of best practice from the `requests source`_ -- place
|
||||
this in your ``__init__.py``
|
||||
this in your ``__init__.py``:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
@@ -83,7 +83,7 @@ There are at least three ways to configure a logger:
|
||||
- Using an INI-formatted file:
|
||||
- **Pro**: possible to update configuration while running using the
|
||||
function :func:`logging.config.listen` to listen on a socket.
|
||||
- **Con**: less control (*e.g.* custom subclassed filters or loggers)
|
||||
- **Con**: less control (e.g. custom subclassed filters or loggers)
|
||||
than possible when configuring a logger in code.
|
||||
- Using a dictionary or a JSON-formatted file:
|
||||
- **Pro**: in addition to updating while running, it is possible to load
|
||||
|
||||
@@ -25,7 +25,7 @@ reading. Each one of these projects is a paragon of Python coding.
|
||||
best intentions in mind.
|
||||
|
||||
- `Diamond <https://github.com/python-diamond/Diamond>`_
|
||||
Diamond is a python daemon that collects metrics
|
||||
Diamond is a Python daemon that collects metrics
|
||||
and publishes them to Graphite or other backends.
|
||||
It is capable of collecting CPU, memory, network, I/O, load, and disk metrics.
|
||||
Additionally, it features an API for implementing custom collectors
|
||||
@@ -36,7 +36,7 @@ reading. Each one of these projects is a paragon of Python coding.
|
||||
applications and has become one of the most advanced WSGI utility modules.
|
||||
It includes a powerful debugger, full-featured request and response objects,
|
||||
HTTP utilities to handle entity tags, cache control headers, HTTP dates,
|
||||
cookie handling, file uploads, a powerful URL routing system and a bunch
|
||||
cookie handling, file uploads, a powerful URL routing system, and a bunch
|
||||
of community-contributed addon modules.
|
||||
|
||||
- `Requests <https://github.com/kennethreitz/requests>`_
|
||||
@@ -49,4 +49,4 @@ reading. Each one of these projects is a paragon of Python coding.
|
||||
|
||||
.. todo:: Include code examples of exemplary code from each of the projects listed. Explain why it is excellent code. Use complex examples.
|
||||
|
||||
.. todo:: Explain techniques to rapidly identify data structures, algorithms and determine what the code is doing.
|
||||
.. todo:: Explain techniques to rapidly identify data structures and algorithms and determine what the code is doing.
|
||||
|
||||
+12
-12
@@ -211,7 +211,7 @@ I highly recommend the latter. Requiring a developer to run
|
||||
codebase also requires them to have an isolated environment setup for
|
||||
each instance of the codebase.
|
||||
|
||||
To give the individual tests import context, create a tests/context.py
|
||||
To give the individual tests import context, create a ``tests/context.py``
|
||||
file:
|
||||
|
||||
::
|
||||
@@ -247,8 +247,8 @@ Makefile
|
||||
|
||||
|
||||
If you look at most of my projects or any Pocoo project, you'll notice a
|
||||
Makefile laying around. Why? These projects aren't written in C... In
|
||||
short, make is a incredibly useful tool for defining generic tasks for
|
||||
Makefile lying around. Why? These projects aren't written in C... In
|
||||
short, make is an incredibly useful tool for defining generic tasks for
|
||||
your project.
|
||||
|
||||
**Sample Makefile:**
|
||||
@@ -334,7 +334,7 @@ include:
|
||||
- Multiple and messy circular dependencies: if your classes
|
||||
Table and Chair in :file:`furn.py` need to import Carpenter from
|
||||
:file:`workers.py` to answer a question such as ``table.isdoneby()``,
|
||||
and if conversely the class Carpenter needs to import Table and Chair,
|
||||
and if conversely the class Carpenter needs to import Table and Chair
|
||||
to answer the question ``carpenter.whatdo()``, then you
|
||||
have a circular dependency. In this case you will have to resort to
|
||||
fragile hacks such as using import statements inside
|
||||
@@ -402,7 +402,7 @@ If you'd like you could name your module :file:`my_spam.py`, but even our
|
||||
friend the underscore should not be seen often in module names. However, using other
|
||||
characters (spaces or hyphens) in module names will prevent importing
|
||||
(- is the subtract operator), so try to keep module names short so there is
|
||||
no need to separate words. And, most of all, don't namespace with underscores, use submodules instead.
|
||||
no need to separate words. And, most of all, don't namespace with underscores; use submodules instead.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
@@ -473,7 +473,7 @@ typing.
|
||||
|
||||
As mentioned in the :ref:`code_style` section, readability is one of the main
|
||||
features of Python. Readability means to avoid useless boilerplate text and
|
||||
clutter, therefore some efforts are spent trying to achieve a certain level of
|
||||
clutter; therefore some efforts are spent trying to achieve a certain level of
|
||||
brevity. But terseness and obscurity are the limits where brevity should stop.
|
||||
Being able to tell immediately where a class or function comes from, as in the
|
||||
``modu.func`` idiom, greatly improves code readability and understandability in
|
||||
@@ -494,7 +494,7 @@ used to gather all package-wide definitions.
|
||||
|
||||
A file :file:`modu.py` in the directory :file:`pack/` is imported with the
|
||||
statement ``import pack.modu``. This statement will look for an
|
||||
:file:`__init__.py` file in :file:`pack`, execute all of its top-level
|
||||
:file:`__init__.py` file in :file:`pack` and execute all of its top-level
|
||||
statements. Then it will look for a file named :file:`pack/modu.py` and
|
||||
execute all of its top-level statements. After these operations, any variable,
|
||||
function, or class defined in :file:`modu.py` is available in the pack.modu
|
||||
@@ -549,9 +549,9 @@ programming, comes from the "state" part of the equation.
|
||||
|
||||
In some architectures, typically web applications, multiple instances of Python
|
||||
processes are spawned to respond to external requests that can happen at the
|
||||
same time. In this case, holding some state into instantiated objects, which
|
||||
same time. In this case, holding some state in instantiated objects, which
|
||||
means keeping some static information about the world, is prone to concurrency
|
||||
problems or race-conditions. Sometimes, between the initialization of the state
|
||||
problems or race conditions. Sometimes, between the initialization of the state
|
||||
of an object (usually done with the ``__init__()`` method) and the actual use
|
||||
of the object state through one of its methods, the world may have changed, and
|
||||
the retained state may be outdated. For example, a request may load an item in
|
||||
@@ -580,7 +580,7 @@ logic (called pure functions) allow the following benefits:
|
||||
- Pure functions are much easier to change or replace if they need to
|
||||
be refactored or optimized.
|
||||
|
||||
- Pure functions are easier to test with unit-tests: There is less
|
||||
- Pure functions are easier to test with unit tests: There is less
|
||||
need for complex context setup and data cleaning afterwards.
|
||||
|
||||
- Pure functions are easier to manipulate, decorate, and pass around.
|
||||
@@ -622,7 +622,7 @@ clearer and thus preferred.
|
||||
# bar() is decorated
|
||||
|
||||
This mechanism is useful for separating concerns and avoiding
|
||||
external un-related logic 'polluting' the core logic of the function
|
||||
external unrelated logic 'polluting' the core logic of the function
|
||||
or method. A good example of a piece of functionality that is better handled
|
||||
with decoration is `memoization <https://en.wikipedia.org/wiki/Memoization#Overview>`__ or caching: you want to store the results of an
|
||||
expensive function in a table and use them directly instead of recomputing
|
||||
@@ -874,7 +874,7 @@ like above or in cases where you are adding to an existing string, using
|
||||
.. note::
|
||||
You can also use the :ref:`% <python:string-formatting>` formatting operator
|
||||
to concatenate a pre-determined number of strings besides :py:meth:`str.join`
|
||||
and ``+``. However, :pep:`3101`, discourages the usage of the ``%`` operator
|
||||
and ``+``. However, :pep:`3101` discourages the usage of the ``%`` operator
|
||||
in favor of the :py:meth:`str.format` method.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
+23
-23
@@ -115,7 +115,7 @@ compared to the more straightforward calls to ``send('Hello', 'World')`` and
|
||||
optional, and evaluate to ``None`` when they are not passed another value.
|
||||
|
||||
Calling a function with keyword arguments can be done in multiple ways in
|
||||
Python, for example it is possible to follow the order of arguments in the
|
||||
Python; for example, it is possible to follow the order of arguments in the
|
||||
definition without explicitly naming the arguments, like in
|
||||
``send('Hello', 'World', 'Cthulhu', 'God')``, sending a blind carbon copy to
|
||||
God. It would also be possible to name arguments in another order, like in
|
||||
@@ -124,7 +124,7 @@ possibilities are better avoided without any strong reason to not follow the
|
||||
syntax that is the closest to the function definition:
|
||||
``send('Hello', 'World', cc='Cthulhu', bcc='God')``.
|
||||
|
||||
As a side note, following `YAGNI <http://en.wikipedia.org/wiki/You_ain't_gonna_need_it>`_
|
||||
As a side note, following the `YAGNI <http://en.wikipedia.org/wiki/You_ain't_gonna_need_it>`_
|
||||
principle, it is often harder to remove an optional argument (and its logic
|
||||
inside the function) that was added "just in case" and is seemingly never used,
|
||||
than to add a new optional argument and its logic when needed.
|
||||
@@ -134,7 +134,7 @@ than to add a new optional argument and its logic when needed.
|
||||
an extensible number of positional arguments, it can be defined with the
|
||||
``*args`` constructs. In the function body, ``args`` will be a tuple of all
|
||||
the remaining positional arguments. For example, ``send(message, *args)``
|
||||
can be called with each recipient as an argument:``send('Hello', 'God',
|
||||
can be called with each recipient as an argument: ``send('Hello', 'God',
|
||||
'Mom', 'Cthulhu')``, and in the function body ``args`` will be equal to
|
||||
``('God', 'Mom', 'Cthulhu')``.
|
||||
|
||||
@@ -181,7 +181,7 @@ possible to do each of the following:
|
||||
|
||||
* change how the Python interpreter imports modules
|
||||
|
||||
* it is even possible (and recommended if needed) to embed C routines in Python.
|
||||
* It is even possible (and recommended if needed) to embed C routines in Python.
|
||||
|
||||
However, all these options have many drawbacks and it is always better to use
|
||||
the most straightforward way to achieve your goal. The main drawback is that
|
||||
@@ -208,7 +208,7 @@ are all responsible users".
|
||||
|
||||
This doesn't mean that, for example, no properties are considered private, and
|
||||
that no proper encapsulation is possible in Python. Rather, instead of relying
|
||||
on concrete walls erected by the developers between their code and other's, the
|
||||
on concrete walls erected by the developers between their code and others', the
|
||||
Python community prefers to rely on a set of conventions indicating that these
|
||||
elements should not be accessed directly.
|
||||
|
||||
@@ -359,7 +359,7 @@ Instead, use a list comprehension:
|
||||
|
||||
four_lists = [[] for __ in xrange(4)]
|
||||
|
||||
Note: Use range() instead of xrange() in Python 3
|
||||
Note: Use range() instead of xrange() in Python 3.
|
||||
|
||||
Create a string from a list
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
@@ -462,7 +462,7 @@ group <http://artifex.org/~hblanks/talks/2011/pep20_by_example.pdf>`_.
|
||||
PEP 8
|
||||
*****
|
||||
|
||||
:pep:`8` is the de-facto code style guide for Python. A high quality,
|
||||
:pep:`8` is the de facto code style guide for Python. A high quality,
|
||||
easy-to-read version of PEP 8 is also available at `pep8.org <http://pep8.org/>`_.
|
||||
|
||||
This is highly recommended reading. The entire Python community does their
|
||||
@@ -520,10 +520,10 @@ Conventions
|
||||
|
||||
Here are some conventions you should follow to make your code easier to read.
|
||||
|
||||
Check if variable equals a constant
|
||||
Check if a variable equals a constant
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
You don't need to explicitly compare a value to True, or None, or 0 - you can
|
||||
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.
|
||||
@@ -608,7 +608,7 @@ Never remove items from a list while you are iterating through it.
|
||||
a.remove(i)
|
||||
|
||||
Don't make multiple passes through the list.
|
||||
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
while i in a:
|
||||
@@ -617,7 +617,7 @@ Don't make multiple passes through the list.
|
||||
**Good**:
|
||||
|
||||
Python has a few standard ways of filtering lists.
|
||||
The approach you use depends on
|
||||
The approach you use depends on:
|
||||
|
||||
* Python 2.x vs. 3.x
|
||||
* Lists vs. iterators
|
||||
@@ -626,19 +626,19 @@ The approach you use depends on
|
||||
Python 2.x vs. 3.x
|
||||
::::::::::::::::::
|
||||
|
||||
Starting with Python 3.0, the :py:func:`filter` function returns an iterator instead of a list.
|
||||
Starting with Python 3.0, the :py:func:`filter` function returns an iterator instead of a list.
|
||||
Wrap it in :py:func:`list` if you truly need a list.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
list(filter(...))
|
||||
|
||||
List comprehensions and generator expressions work the same in both 2.x and 3.x (except that comprehensions in 2.x "leak" variables into the enclosing namespace)
|
||||
List comprehensions and generator expressions work the same in both 2.x and 3.x (except that comprehensions in 2.x "leak" variables into the enclosing namespace):
|
||||
|
||||
* comprehensions create a new list object
|
||||
* generators iterate over the original list
|
||||
* Comprehensions create a new list object.
|
||||
* Generators iterate over the original list.
|
||||
|
||||
The :py:func:`filter` function
|
||||
The :py:func:`filter` function:
|
||||
|
||||
* in 2.x returns a list (use itertools.ifilter if you want an iterator)
|
||||
* in 3.x returns an iterator
|
||||
@@ -653,14 +653,14 @@ Creating a new list requires more work and uses more memory. If you a just going
|
||||
# comprehensions create a new list object
|
||||
filtered_values = [value for value in sequence if value != x]
|
||||
# Or (2.x)
|
||||
filtered_values = filter(lambda i: i != x, sequence)
|
||||
filtered_values = filter(lambda i: i != x, sequence)
|
||||
|
||||
# generators don't create another list
|
||||
filtered_values = (value for value in sequence if value != x)
|
||||
# Or (3.x)
|
||||
filtered_values = filter(lambda i: i != x, sequence)
|
||||
# Or (2.x)
|
||||
filtered_values = itertools.ifilter(lambda i: i != x, sequence)
|
||||
filtered_values = itertools.ifilter(lambda i: i != x, sequence)
|
||||
|
||||
|
||||
|
||||
@@ -678,7 +678,7 @@ Modifying the original list can be risky if there are other variables referencin
|
||||
# Or
|
||||
sequence[::] = filter(lambda value: value != x, sequence)
|
||||
|
||||
|
||||
|
||||
Modifying the values in a list
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
**Bad**:
|
||||
@@ -690,26 +690,26 @@ Remember that assignment never creates a new object. If two or more variables re
|
||||
# Add three to all list members.
|
||||
a = [3, 4, 5]
|
||||
b = a # a and b refer to the same list object
|
||||
|
||||
|
||||
for i in range(len(a)):
|
||||
a[i] += 3 # b[i] also changes
|
||||
|
||||
**Good**:
|
||||
|
||||
It's safer to create a new list object and leave the original alone.
|
||||
It's safer to create a new list object and leave the original alone.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
a = [3, 4, 5]
|
||||
b = a
|
||||
|
||||
|
||||
# assign the variable "a" to a new list without changing "b"
|
||||
a = [i + 3 for i in a]
|
||||
# Or (Python 2.x):
|
||||
a = map(lambda i: i + 3, a)
|
||||
# Or (Python 3.x)
|
||||
a = list(map(lambda i: i + 3, a))
|
||||
|
||||
|
||||
|
||||
Use :py:func:`enumerate` keep a count of your place in the list.
|
||||
|
||||
|
||||
@@ -81,7 +81,7 @@ The Basics
|
||||
**********
|
||||
|
||||
|
||||
Unittest
|
||||
unittest
|
||||
--------
|
||||
|
||||
:mod:`unittest` is the batteries-included test module in the Python standard
|
||||
@@ -170,7 +170,7 @@ functions:
|
||||
def test_answer():
|
||||
assert func(3) == 5
|
||||
|
||||
and then running the `py.test` command
|
||||
and then running the `py.test` command:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
@@ -236,14 +236,14 @@ tox
|
||||
---
|
||||
|
||||
tox is a tool for automating test environment management and testing against
|
||||
multiple interpreter configurations
|
||||
multiple interpreter configurations.
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
$ pip install tox
|
||||
|
||||
tox allows you to configure complicated multi-parameter test matrices via a
|
||||
simple ini-style configuration file.
|
||||
simple INI-style configuration file.
|
||||
|
||||
`tox <https://tox.readthedocs.io/en/latest/>`_
|
||||
|
||||
@@ -254,7 +254,7 @@ Unittest2
|
||||
unittest2 is a backport of Python 2.7's unittest module which has an improved
|
||||
API and better assertions over the one available in previous versions of Python.
|
||||
|
||||
If you're using Python 2.6 or below, you can install it with pip
|
||||
If you're using Python 2.6 or below, you can install it with pip:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
@@ -326,4 +326,3 @@ always returns the same result (but only for the duration of the test).
|
||||
Mock has many other ways you can configure it and control its behavior.
|
||||
|
||||
`mock <http://www.voidspace.org.uk/python/mock/>`_
|
||||
|
||||
|
||||
Reference in New Issue
Block a user