|
|
(24 intermediate revisions by one other user not shown) |
Line 1: |
Line 1: |
| = Python =
| | {{admon/important|This page is deprecated| All Fedora Modularity Documentation has moved to the new [https://docs.pagure.org/modularity/ Fedora Modularity Documentation website] with source hosted along side the code in the [https://pagure.io/modularity Fedora Modularity website git repository]}} |
| | |
| Most of our code is written in Python, so this document will concentrate on it.
| |
| | |
| == PEP 8: Official Python Style Guide ==
| |
| | |
| Fortunately, with PEP 8 there's an official [https://www.python.org/dev/peps/pep-0008/ Style Guide for Python Code]. All new Python code you submit should conform to it, unless you have good reasons to deviate from it, [https://www.python.org/dev/peps/pep-0008/#id15 for instance readability].
| |
| | |
| == Keep It Simple ==
| |
| | |
| The code you write now probably needs to be touched by someone else down the road, and that someone else might be less experienced than you, or have a terrible headache and be under pressure of time. So while a particular construct may be a clever way of doing something, a simple way of doing the same thing can be and often is preferrable.
| |
| | |
| == New-style classes ==
| |
| | |
| Python 2 and earlier knows two types of classes, old-style which have no base class, and new-style which have <code>object</code> as the base class. Because their behavior is slightly different in some places, and some things can't be done with old-style classes, we want to stick to new-style classes wherever possible.
| |
| | |
| The syntactical difference is that new-style classes have to explicitly be derived from <code>object</code> or another new-style class.
| |
| | |
| <pre>
| |
| # old-style classes
| |
| class OldFoo:
| |
| pass
| |
| | |
| class OldBar(OldFoo):
| |
| pass
| |
| | |
| # new-style classes
| |
| class NewFoo(object):
| |
| pass
| |
| | |
| class NewBar(NewFoo):
| |
| pass
| |
| </pre>
| |
| | |
| Python 3 only knows new-style classes and the requirement to derive from <code>object</code> was dropped. In projects that will only ever run on Python 3, it's acceptable not to explicitly derive classes without parents from <code>object</code>, but if in doubt, do it just the same.
| |
| | |
| == Idiomatic code ==
| |
| | |
| In Python, it's easy to inadvertently emulate idiomatic styles of other languages like C/C++ or Java. In cases where there are constructs "native" to the language, it's preferrable to use them.
| |
| | |
| Here are some examples:
| |
| | |
| === Looping ===
| |
| | |
| Languages like C normally use incremented indices to loop over arrays:
| |
| | |
| <pre>
| |
| float pixels[NUMBER_OF_PIXELS] = [...];
| |
| | |
| for (int i = 0; i < NUMBER_OF_PIXELS; i++)
| |
| {
| |
| do_something_with_a_pixel(pixels[i]);
| |
| }
| |
| </pre>
| |
| | |
| {{admon/warning|Looping C-style in Python|Please avoid looping over indices of sequences, rather than the sequences themselves in Python.}}
| |
| | |
| Implementing the loop like this would give away that you've programmed in C or a similar language before:
| |
| | |
| <pre>
| |
| pixels = [...]
| |
| | |
| for i in range(len(pixels)):
| |
| do_something_with_a_pixel(pixels[i])
| |
| </pre>
| |
| | |
| {{admon/note|Looping over iterables in Python|In Python, you can simply iterate over many non-scalar data types.}}
| |
| | |
| Here's the "native" way to implement the above loop:
| |
| | |
| <pre>
| |
| pixels = [...]
| |
| | |
| for p in pixels:
| |
| do_something_with_a_pixel(p)
| |
| </pre>
| |
| | |
| {{admon/tip|Using <code>enumerate()</code>|If you need to keep track of the current count of looped-over items, use the <code>enumerate()</code> built-in.}}
| |
| | |
| It yields pairs of count and the current value like this:
| |
| | |
| <pre>
| |
| pixels = [...]
| |
| | |
| for i, p in enumerate(pixels):
| |
| print("Working on pixel no. {}".format(i + 1))
| |
| do_something_with_a_pixel(p)
| |
| </pre>
| |
| | |
| === Properties rather than explicit accessor methods ===
| |
| | |
| In order to allow future changes in how object attributes (member variables) are set, some languages encourage always using getter and/or setter methods. This is unnecessary in Python, as you can intercept attribute access by wrapping it into a property.
| |
| | |
| TBD
| |