Code Style
Pythonistas (veteran Python developers) celebrate having a language so accessible that people who have never programmed can still understand what a Python program does when they read its source code. Readability is at the heart of Python’s design, following the recognition that code is read much more often than it is written.One reason Python code can be easily understood is its relatively complete set of code style guidelines (collected in the two Python Enhancement Proposals PEP 20 ,described next) and “Pythonic” idioms. When a Pythonista points to portions of code and says they are not “Pythonic,” it usually means that those lines of code do not follow the common guidelines and fail to express the intent in what is considered the most readable way. Of course, “a foolish consistency is the hobgoblin of little minds". Pedantic devotion to the letter of the PEP can underminereadability and understandability.
PEP 20; Zen of Python
In the world of scripting languages, Python is a relative newcomer to the scene, though not as recent as many people believe. As mentioned in earlier posts it was developed in the late 1980s, perhaps 15 years after the conception of Unix. It was implemented in December 1989 by its principal author, Guido Van Rossum. He has remained active in Python’s development and progress, and his contributions to the language have been rewarded by the Python community, which gifted him with the title Benevolent Dictator For Life (BDFL).Python’s philosophy has always been to make code readable and accessible. That philosophy has been summed up in Python’s “PEP 20 (The Zen Of Python)” document, which reads as follows:
• 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!
In addition to these commandments, Python has a “batteries included” mindset, which means that whatever
strange task you need to do in Python, chances are good that a module already exists to do just that, so you don’t have to reinvent the wheel.
General advice
This section contains style concepts that are hopefully easy to accept without debate, and often applicable to languages other than Python. Some of them are direct from the Zen of Python, but others are just plain common sense. They reaffirm our preference in Python to select the most obvious way to present code, when multiple options are possible.
Explicit is better than implicit
While any kind of black magic is possible with Python, the simplest, most explicit way to express something is preferred:
Bad | Good |
---|---|
def make_dict(*args): x, y = args return dict(**locals()) |
def make_dict(x, y): return {'x': x, 'y': y} |
In the good code, x and y are explicitly received from the caller, and an explicit dictionary is returned. A good rule of thumb is that another developer should be able to read the first and last lines of your function and understand what it does. That’s not the case with the bad example. (Of course, it’s also pretty easy when the function is only two lines long)
Sparse is better than dense
Make only one statement per line. Some compound statements, such as list comprehensions, are allowed and appreciated for their brevity and their expressiveness, but it is good practice to keep disjoint statements on separate lines of code. It also makes for more understandable diffs(diff is a shell utility that identifies and shows lines that differ between two files) when revisions to one statement are made:
Bad | Good |
---|---|
print('one'); print('two') if x == 1: print('one') if (<complex comparison> and <other complex comparison>): # do something |
print('one') print('two') if x == 1: print('one') cond1 = <complex comparison> cond2 = <other complex comparison> if cond1 and cond2: # do something |
Errors should never pass silently / Unless explicitly silenced
def format_output(code, args):
if not args['color']:
return code
lexer = None
# try to find a lexer using the Stack Overflow tags
# or the query arguments
for keyword in args['query'].split() + args['tags']:
try:
lexer=getlexerbyname(keyword)
break
except ClassNotFound:
# no lexer found above, use the guesser
if not lexer:
lexer = guess_lexer(code)
return highlight(code,lexer,TerminalFormatter(bg='dark'))
if not args['color']:
return code
lexer = None
# try to find a lexer using the Stack Overflow tags
# or the query arguments
for keyword in args['query'].split() + args['tags']:
try:
lexer=getlexerbyname(keyword)
break
except ClassNotFound:
# no lexer found above, use the guesser
if not lexer:
lexer = guess_lexer(code)
return highlight(code,lexer,TerminalFormatter(bg='dark'))
This is part of a package that provides a command-line script to query the Internet (Stack Overflow, by default) for how to do a particular coding task, and prints it to the screen. The function format_output() applies syntax highlighting by first search‐
ing through the question’s tags for a string understood by the lexer (also called a tokenizer; a “python”, “java”, or “bash” tag will identify which lexer to use to split and colorize the code), and then if that fails, to try inferring the language from the code itself. There are three paths the program can follow when it reaches the try statement:
•Execution enters the try clause (everything between the try and the except), a lexer is successfully found, the loop breaks, and the function returns the code highlighted with the selected lexer.
• The lexer is not found, the ClassNotFound exception is thrown, it’s caught, and nothing is done. The loop continues until it finishes naturally or a lexer is found.
• Some other exception occurs (like a KeyboardInterrupt) that is not handled, and it is raised up to the top level, stopping execution.
The “should never pass silently” part of the zen aphorism discourages the use of over‐zealous error trapping. Here’s an example you can try in a separate terminal so that you can kill it more easily once you get the point:
>>> while True:
... try:
... print("nyah", end=" ")
... except:
... pass
Or don’t try it. The except clause without any specified exception will catch everything, including KeyboardInterrupt (Ctrl+C in a POSIX terminal), and ignore it; so it swallows the dozens of interrupts you try to give it to shut the thing down. It’s not just the interrupt issue—a broad except clause can also hide bugs, leaving them to cause some problem later on, when it will be harder to diagnose. We repeat, don’t let errors pass silently: always explicitly identify by name the exceptions you will catch, and handle only those exceptions. If you simply want to log or otherwise acknowledge the exception and re-raise it, like in the following snippet, that’s OK. Just don’t let the error pass silently (without handling or re-raising it):
•Execution enters the try clause (everything between the try and the except), a lexer is successfully found, the loop breaks, and the function returns the code highlighted with the selected lexer.
• The lexer is not found, the ClassNotFound exception is thrown, it’s caught, and nothing is done. The loop continues until it finishes naturally or a lexer is found.
• Some other exception occurs (like a KeyboardInterrupt) that is not handled, and it is raised up to the top level, stopping execution.
The “should never pass silently” part of the zen aphorism discourages the use of over‐zealous error trapping. Here’s an example you can try in a separate terminal so that you can kill it more easily once you get the point:
>>> while True:
... try:
... print("nyah", end=" ")
... except:
... pass
Or don’t try it. The except clause without any specified exception will catch everything, including KeyboardInterrupt (Ctrl+C in a POSIX terminal), and ignore it; so it swallows the dozens of interrupts you try to give it to shut the thing down. It’s not just the interrupt issue—a broad except clause can also hide bugs, leaving them to cause some problem later on, when it will be harder to diagnose. We repeat, don’t let errors pass silently: always explicitly identify by name the exceptions you will catch, and handle only those exceptions. If you simply want to log or otherwise acknowledge the exception and re-raise it, like in the following snippet, that’s OK. Just don’t let the error pass silently (without handling or re-raising it):
>>> while True:
... try:
... print("ni", end="-")
... except:
... print("An exception happened. Raising.")
... raise
More about Python code style will be discussed later. Without getting started with Python discussing about Python code style will become ridiculous.... try:
... print("ni", end="-")
... except:
... print("An exception happened. Raising.")
... raise
Comments
Post a Comment