Python Programming/Idioms

Python is a strongly idiomatic language: there is generally a single optimal way of doing something (a ), rather than many ways: “There’s more than one way to do it” is not a Python motto.

This section starts with some general principles, then goes through the language, highlighting how to idiomatically use operations, data types, and modules in the standard library.

Principles
Use exceptions for error-checking, following EAFP (It's Easier to Ask Forgiveness than Permission) instead of LBYL (Look Before You Leap): put an action that may fail inside a  block.

Use context managers for managing resources, like files. Use  for ad hoc cleanup, but prefer to write a context manager to encapsulate this.

Use properties, not getter/setter methods.

Use dictionaries for dynamic records, classes for static records (for simple classes, use collections.namedtuple): if a record always has the same fields, make this explicit in a class; if the fields may vary (be present or not), use a dictionary.

Use  for throwaway variables, like discarding a return value when a tuple is returned, or to indicate that a parameter is being ignored (when required for an interface, say). You can use  to discard positional or keyword arguments passed to a function: these correspond to the usual   parameters, but explicitly discarded. You can also use these in addition to positional or named parameters (following the ones you use), allowing you to use some and discard any excess ones.

Use implicit True/False (truthy/falsy values), except when needing to distinguish between falsy values, like None, 0, and [], in which case use an explicit check like  or.

Use the optional  clause after   not just.

Imports
For readable and robust code, only import modules, not names (like functions or classes), as this creates a new (name) binding, which is not necessarily in sync with the existing binding. For example, given a module  which defines a function , importing the function with   means that   and   can differ if either is assigned to (creating a new binding).

In practice, this is frequently ignored, particularly for small-scale code, as changing a module post-import is rare, so this is rarely a problem, and both classes and functions are imported from modules so they can be referred to without a prefix. However, for robust, large-scale code, this is an important rule, as it risks creating very subtle bugs.

For robust code with low typing, one can use a renaming import to abbreviate a long module name:

Note that importing submodules (or subpackages) from a package using  is completely fine:

Operations

 * Swap values

To access an attribute (esp. to call a method) on a value that might be an object, or might be, use the boolean shortcircuiting of  : Particularly useful for regex matches:
 * Attribute access on nullable value

Use  for substring checking.
 * in

All sequence types
Use  if you need to keep track of iteration cycles over an iterable: Anti-idiom:
 * Indexing during iteration

Python sequences do have an  method, but this returns the index of the first occurrence of a specific value in the sequence. To find the first occurrence of a value that satisfies a condition, instead, use  and a generator expression:
 * Finding first matching element

If you need the value, not the index of its occurrence, you can get it directly through:

The reason for this construct is twofold:
 * Exceptions let you signal “no match found” (they solve the semipredicate problem): since you're returning a single value (not an index), this can't be returned in the value.
 * Generator expressions let you use an expression without needing a lambda or introducing new grammar.

For mutable sequences, use, instead of reassigning to a slice: Anti-idiom: The simplest reason is that  makes your intention clear: you're truncating.
 * Truncating

More subtly, slicing creates another reference to the same list (because lists are mutable), and then unreachable data can be garbage-collected, but generally this is done later. Deleting instead immediately modifies the list in-place (which is faster than creating a slice and then assigning it to the existing variable), and allows Python to immediately deallocate the deleted elements, instead of waiting for garbage collection.

In some cases you do want 2 slices of the same list – though this is rare in basic programming, other than iterating once over a slice in a  loop – but it's rare that you'll want to make a slice of a whole list, then replace the original list variable with a slice (but not change the other slice!), as in the following funny-looking code:

You can create a sorted list directly from any iterable, without needing to first make a list and then sort it. These include sets and dictionaries (iterate on the keys):
 * Sorted list from an iterable

Tuples
Use tuples for constant sequences. This is rarely necessary (primarily when using as keys in a dictionary), but makes intention clear.

Strings
Use  for substring checking.
 * Substring

However, do not use  to check if a string is a single-character match, since it matches substrings and will return spurious matches – instead use a tuple of valid values. For example, the following is wrong: Instead, use a tuple:

To make a long string incrementally, build a list and then join it with  – or with newlines, if building a text file (don't forget the final newline in this case!). This is faster and clearer than appending to a string, which is often slow. (In principle can be $$O(nk)$$ in overall length of string and number of additions, which is $$O(n^2)$$ if pieces are of similar sizes.)
 * Building a string

However, there are some optimizations in some versions CPython that make simple string appending fast – string appending in CPython 2.5+, and bytestring appending in CPython 3.0+ are fast, but for building Unicode strings (unicode in Python 2, string in Python 3), joining is faster. If doing extensive string manipulation, be aware of this and profile your code. See Performance Tips: String Concatenation and Concatenation Test Code for details.

Don't do this: Instead: You can even use generator expressions, which are extremely efficient:

If you do want a mutable string-like object, you can use.


 * Efficient String Concatenation in Python – old article (so benchmarks out of date), but gives overview of some techniques.

Dictionaries
To iterate through a dictionary, either keys, values, or both: Anti-patterns:

FIXME:
 * setdefault
 * usually better to use collections.defaultdict

is useful, but using  and then checking if it is   as a way of testing if the key is in the dictionary is an anti-idiom, as   is a potential value, and whether the key is in the dictionary can be checked directly. It's ok to use  and compare with   if this is not a potential value, however.

Simple:

Anti-idiom (unless  is not a potential value):

Use  as:
 * Dict from parallel sequences of keys and values

re
Match if found, else : ...returns  if no match, and the match contents if there is one.