As someone who evangelizes Python at work, I read a lot of code written by
professional programmers new to Python. I've written a good amount of Python
code in my time, but I've certainly read far more. The single quickest way to
increase maintainability and decrease 'simple' bugs is to strive to write
idiomatic Python. Whereas some dynamic languages embrace the idea there being
no 'right' way to solve a problem, the Python community generally appreciates
the liberal use of 'Pythonic' solutions to problems. 'Pythonic' refers to the
principles laid out in 'The Zen of Python' (try typing 'import this' in an
interpreter...). One of those principles is
'There should be one-- and preferably only one --obvious way to do it'-from'The Zen of Python'byTimPeters
In that vein, I've begun compiling a list of Python idioms that programmers
coming from other languages may find helpful. I know there are a ton of things
not on here; it's merely a skeleton list that I'll add to over time. If you have
a specific idiom you think should be added, let me know in the comments and I'll
add it with attribution to the name you use in your comment.
This list will temporarily live here as a blog post, but I have an interesting
idea for its final home. More on that next week.
Update: The 'Writing Idiomatic Python' e-Book is here!
Python has a language-defined standard set of formatting rules known as PEP8. If you're browsing commit messages on Python projects, you'll likely find them littered with references to PEP8 cleanup. The reason is simple: if we all agree on a common set of naming and formatting conventions, Python code as a whole becomes instantly more accessible to both novice and experienced developers. PEP8 is perhaps the most explicit example of idioms within the Python community. Read the PEP, install a PEP8 style-checking plugin for your editor (they all have one), and start writing your code in a way that other Python developers will appreciate. Listed below are a few examples.
Identifier Type|Format|Example
----|------|-------|----
Class|Camel case|class StringManipulator:
Variable|Words joined by underscore| words_joined_by_underscore = True
Function|Words joined by underscore| def are_words_joined_by_underscore(words):
'Internal' class members/functions| Prefixed by single underscore| def _update_statistics(self):
Unless wildly unreasonable, abbreviations should not be used (acronyms are fine if in common use, like 'HTTP')
Working With Data
Avoid using a temporary variable when swapping two variables
There is no reason to swap using a temporary variable in Python. We can use
tuples to make our intention more clear.
Harmful
123
temp=foofoo=barbar=temp
Idiomatic
1
(foo,bar)=(bar,foo)
Use tuples to unpack data
In Python, it is possible to 'unpack' data for multiple assignment. Those familiar with LISP may know this as 'desctructuring bind'.
Use ''.join when creating a single string for list elements
It's faster, uses less memory, and you'll see it everywhere anyway. Note that
the two quotes represent the delimiter between list elements in the string we're
creating.''just means we mean to concatenate the elements with no characters
between them.
Harmful
1234
result_list=['True','False','File not found']result_string=''forresultinresult_list:result_string+=result
Idiomatic
12
result_list=['True','False','File not found']result_string=''.join(result_list)
Use the 'default' parameter of dict.get() to provide default values
Often overlooked in the get() definition is the default parameter. Without
using default (or the collections.defaultdict class), your code will be
littered with confusing if statements. Remember, strive for clarity.
Use Context Managers to ensure resources are properly managed
Similar to the RAII principle in languages like C++ and D, context managers
(objects meant to be used with the with statement) can make resource
management both safer and more explicit. The canonical example is file IO.
Harmful
12345
file_handle=open(path_to_file,'r')forlineinfile_handle.readlines():ifsome_function_that_throws_exceptions(line):# do somethingfile_handle.close()
Idiomatic
12345
withopen(path_to_file,'r')asfile_handle:forlineinfile_handle:ifsome_function_that_throws_exceptions(line):# do something# No need to explicitly call 'close'. Handled by the File context manager
In the Harmful code above, what happens if some_function_that_throws_exceptions does, in fact, throw an exception? Since we haven't caught it in the code listed, it will propagate up the stack. We've hit an exit point in our code that might have been overlooked, and we now have no way to close the opened file. In addition to those in the standard libraries (for working with things like file IO, synchronization, managing mutable state) developers are free to create their own.
Learn the contents of the itertools module
If you frequent sites like StackOverflow, you may notice that the answer to questions of the form "Why doesn't Python have the following obviously useful library function?" almost always references the itertools module. The functional programming stalwarts that itertools provides should be seen as fundamental building blocks. What's more, the documentation for itertools has a 'Recipes' section that provides idiomatic implementations of common functional programming constructs, all created using the itertools module. For some reason, a vanishingly small number of Python developers seem to be aware of the 'Recipes' section and, indeed, the itertools module in general (hidden gems in the Python documentation is actually a recurring theme). Part of writing idiomatic code is knowing when you're reinventing the wheel.
Control Structures
If Statement
Avoid placing conditional branch on the same line as the colon
Using indentation to indicate scope (like you already do everywhere
else in Python) makes it easy to determine what will be executed as part of a
conditional statement.
Harmful
12
ifname:print(name)printaddress
Idiomatic
123
ifname:print(name)printaddress
Avoid having multiple statements on a single line
Though the language definition allows one to use a semi-colon to delineate
statements, doing so without reason makes one's code harder to read. Typically
violated with the previous rule.
Avoid repeating variable name in compound if Statement
When one wants to check against a number of values, repeatedly listing the
variable whose value is being checked is unnecessarily verbose. Using a temporary
collection makes the intention clear.
Use list comprehensions to create lists that are subsets of existing data
List comprehensions, when used judiciously, increase clarity in code that
builds a list from existing data. Especially when data is both checked for some
condition and transformed in some way, list comprehensions make it clear
what's happening. There are also (usually) performance benefits to using list
comprehensions (or alternately, set comprehensions) due to optimizations in the
CPython interpreter.
Programmers coming languages lacking a for_each style construct are used to
iterating over a container by accessing elements via index. Python's in
keyword handles this gracefully.