Python Code Style Fix Notes
Motivation
I am working on fixing some of the issues raised by flake8 (a Python Linter) in a Python-based backend repository and thought it would be nice to discuss some of the common issues and the solutions that I gathered from the web (well, mostly StackOverflow). The use of an auto formatter such as black will help resolve some of these common issues automatically. flake8rules is an excellent resource of a complete list of issues as well.
line too long (92 > 79 characters)flake8(E501)
Line too long issues mainly happen for the following cases:
- string
- if-statement
- method chaining
- parameter list
... I was going to explain with examples how to use Python's implied line continuation inside parentheses, brackets and braces but decided not to. Nowadays I chose to leave it to my auto formatter to do the job.
For those who insist to write code without any helpful plugins or IDE support, I would like to share that practice does make perfect. I used Vim for a period of writing Java code without autocomplete or format-on-save. I ran style checks and manually fixed issues raised such as having a space between operators. After a month or two, these things became second nature and I was pretty happy with the ability to write well-formatted code without any help. I suppose that was an interesting experience so go ahead and try it yourself.
do not use bare 'except'flake8(E722)
Example:
def create(item):
try:
item("creating")
except:
pass
Fix:
def create(item):
try:
item("creating")
except Exception:
pass
Explanation:
Bare except will catch exceptions you almost certainly don't want to catch, including KeyboardInterrupt (the user hitting Ctrl+C) and Python-raised errors like SystemExit
A better fix:
- Think about what exact exception to catch and specify that instead of just catching any exception.
- Think about whether this exception handling is necessary and are you unintentionally using it for control flow?
- When catching an exception, use either logging or other proper resolutions to handle the anticipated error.
'from some_package_name_here import *' used; unable to detect undefined names flake8(F403)
I thought this is an interesting topic for discussion. Earlier in my coding journey, I was amused by the many lines of import statements found in some scripts. Sometimes the number of import statements outweigh the number of practical code within the same file.
Nowadays I know better than to fear abstractions (I still fear BAD abstractions and rightfully so). However, with the help of powerful IDEs, importing and tracing the variable/function to their imported package is easier than before. The problem with 'from xxx import *' is that it is unclear what has been imported. Following this, IDEs could not decide whether some of the undefined variables come from the package that you imported or they are errors.
Example
from package_a import *
from package_b import *
# suppose both packages included a function named pretty_print
# it is unclear which method is invoked below
pretty_print("abc")
Fix
from package_a import pretty_print
from package_b import other_function_required
pretty_print("abc")
Conclusion
When browsing an unfamiliar code repository, we tend to have less sentimental feelings and that fresh perspective allows us to see the good, the bad, and the evil. Besides learning from the good practices, the hacky and the code standard violations (and things like commented out code) are excellent places to start reviewing concepts of coding styles and coding standards, to find out why code misbehaved.
That's all for now.