1. 程式人生 > >PyCharm 使用 autopep8 按 PEP8 風格自動排版 Python 程式碼!

PyCharm 使用 autopep8 按 PEP8 風格自動排版 Python 程式碼!

autopep8 是一個將 Python 程式碼自動排版為 PEP8 風格的小工具。它使用 pep8 工具來決定程式碼中的哪部分需要被排版。autopep8 可以修復大部分 pep8 工具中報告的排版問題。

PyCharm 使用 autopep8 按 PEP8 風格自動排版 Python 程式碼

更新記錄

2018 年 12 月 27 日 - 初稿

閱讀原文 - https://wsgzao.github.io/post/autopep8/

擴充套件閱讀

autopep8 - https://pypi.python.org/pypi/autopep8/

autopep8 簡介

使用 autopep8 前我們有必要先了解下 PEP 8 – Style Guide for Python Code

autopep8 automatically formats Python code to conform to the PEP 8 style guide. It uses the pycodestyle utility to determine what parts of the code needs to be formatted. autopep8 is capable of fixing most of the formatting issues that can be reported by pycodestyle.

進群:960410445  即可獲取數十套PDF!

https://www.python.org/dev/peps/pep-0008/

https://pypi.python.org/pypi/autopep8/

安裝和使用 autopep8

autopep8 是一個開源的命令列工具,它能夠將 Python 程式碼自動格式化為 PEP8 風格。autopep8 使用 pycodestyle 工具來決定程式碼中的哪部分需要被格式化,這能夠修復大部分 pycodestyle 工具中報告的排版問題。autopep8 本身也是一個 Python 語言編寫的工具,因此,我們可以直接使用 pip 進行安裝:

pip install autopep8
autopep8 --in-place optparse.py 
# To modify a file in place (with aggressive level 2):
autopep8 --in-place --aggressive --aggressive <filename>
usage: autopep8 [-h] [--version] [-v] [-d] [-i] [--global-config filename]
 [--ignore-local-config] [-r] [-j n] [-p n] [-a]
 [--experimental] [--exclude globs] [--list-fixes]
 [--ignore errors] [--select errors] [--max-line-length n]
 [--line-range line line] [--hang-closing] [--exit-code]
 [files [files ...]]
Automatically formats Python code to conform to the PEP 8 style guide.
positional arguments:
 files files to format or '-' for standard in
optional arguments:
 -h, --help show this help message and exit
 --version show program's version number and exit
 -v, --verbose print verbose messages; multiple -v result in more
 verbose messages
 -d, --diff print the diff for the fixed source
 -i, --in-place make changes to files in place
 --global-config filename
 path to a global pep8 config file; if this file does
 not exist then this is ignored (default:
 ~/.config/pep8)
 --ignore-local-config
 don't look for and apply local config files; if not
 passed, defaults are updated with any config files in
 the project's root directory
 -r, --recursive run recursively over directories; must be used with
 --in-place or --diff
 -j n, --jobs n number of parallel jobs; match CPU count if value is
 less than 1
 -p n, --pep8-passes n
 maximum number of additional pep8 passes (default:
 infinite)
 -a, --aggressive enable non-whitespace changes; multiple -a result in
 more aggressive changes
 --experimental enable experimental fixes
 --exclude globs exclude file/directory names that match these comma-
 separated globs
 --list-fixes list codes for fixes; used by --ignore and --select
 --ignore errors do not fix these errors/warnings (default:
 E226,E24,W50,W690)
 --select errors fix only these errors/warnings (e.g. E4,W)
 --max-line-length n set maximum allowed line length (default: 79)
 --line-range line line, --range line line
 only fix errors found within this inclusive range of
 line numbers (e.g. 1 99); line numbers are indexed at
 1
 --hang-closing hang-closing option passed to pycodestyle
 --exit-code change to behavior of exit code. default behavior of
 return value, 0 is no differences, 1 is error exit.
 return 2 when add this option. 2 is exists
 differences.

–in-place 類似於 sed 命令的 - i 選項,如果不包含 –in-place 選項,則會將 autopep8 格式化以後的程式碼直接輸出到控制檯。我們可以使用這種方式檢查 autopep8 的修改,使用 –in-place 則會直接將結果儲存到原始檔中。

我們來看一個完整的例子,本例中使用的程式碼如下:

import os, sys 
 
def main(): 
 print [item for item in os.listdir('.') if item.endswith('.py')]; 
 print sys.version 
 
if __name__ == '__main__': 
 main()

這段程式碼存在三個問題:

  1. 匯入的時候,應該每一行只匯入一個包;
  2. 包匯入和函式定義之間應該空兩行;
  3. Python 程式碼末尾不需要分號。

接下來,我們將使用 pycodestyple 檢查這段程式碼,然後使用 autopep8 將程式碼格式化成符合 PEP 8 風格的程式碼。

使用 pycodestyle 檢查程式碼可檢測到程式碼中有三個地方不符合 PEP 8 規範,如下所示:

pycodestyle hello.py 
hello.py:1:10: E401 multiple imports on one line 
hello.py:3:1: E302 expected 2 blank lines, found 1 
hello.py:4:69: E703 statement ends with a semicolon

使用 autopep8 格式能夠轉換 Python 程式碼。在這個例子中,autopep8 順利地幫我們修復了所有問題,如下所示:

$ autopep8 hello.py 
import os 
import sys 
 
 
def main(): 
 print [item for item in os.listdir('.') if item.endswith('.py')] 
 print sys.version 
 
 
if __name__ == '__main__': 
 main()

這個時候如果檢視原始檔的話,會發現還是和原來一樣,並沒有修正為符合 PEP 8 規範的程式碼。前面說過,不指定 –in-place 選項,只會將結果輸出到命令列。如果我們使用 –in-place 選項,將不會有任何輸出,autopep8 會直接修改原始檔。

$ autopep8 --in-place hello.py

autopep8 還存在 –aggressive 選項,使用該選項會執行更多實質性的更改,可以多次使用以達到更佳的效果。

以官網為例我們編寫一個 test_autopep8.py

Before running autopep8.
import math, sys;
def example1():
 ####This is a long comment. This should be wrapped to fit within 72 characters.
 some_tuple=( 1,2, 3,'a' );
 some_variable={'long':'Long code lines should be wrapped within 79 characters.',
 'other':[math.pi, 100,200,300,9876543210,'This is a long string that goes on'],
 'more':{'inner':'This whole logical line should be wrapped.',some_tuple:[1,
 20,300,40000,500000000,60000000000000000]}}
 return (some_tuple, some_variable)
def example2(): return {'has_key() is deprecated':True}.has_key({'f':2}.has_key(''));
class Example3( object ):
 def __init__ ( self, bar ):
 #Comments should have a space after the hash.
 if bar : bar+=1; bar=bar* bar ; return bar
 else:
 some_string = """
 Indentation in multiline strings should not be touched.
Only actual code should be reindented.
"""
 return (sys.path, some_string)
After running autopep8.
import math
import sys
def example1():
 # This is a long comment. This should be wrapped to fit within 72
 # characters.
 some_tuple = (1, 2, 3, 'a')
 some_variable = {
 'long': 'Long code lines should be wrapped within 79 characters.',
 'other': [
 math.pi,
 100,
 200,
 300,
 9876543210,
 'This is a long string that goes on'],
 'more': {
 'inner': 'This whole logical line should be wrapped.',
 some_tuple: [
 1,
 20,
 300,
 40000,
 500000000,
 60000000000000000]}}
 return (some_tuple, some_variable)
def example2(): return ('' in {'f': 2}) in {'has_key() is deprecated': True}
class Example3(object):
 def __init__(self, bar):
 # Comments should have a space after the hash.
 if bar:
 bar += 1
 bar = bar * bar
 return bar
 else:
 some_string = """
 Indentation in multiline strings should not be touched.
Only actual code should be reindented.
"""
 return (sys.path, some_string)

autopep8 可以修復的問題

autopep8 fixes the following issues reported by pycodestyle:

https://github.com/PyCQA/pycodestyle

E101 - Reindent all lines.
E11 - Fix indentation.
E121 - Fix indentation to be a multiple of four.
E122 - Add absent indentation for hanging indentation.
E123 - Align closing bracket to match opening bracket.
E124 - Align closing bracket to match visual indentation.
E125 - Indent to distinguish line from next logical line.
E126 - Fix over-indented hanging indentation.
E127 - Fix visual indentation.
E128 - Fix visual indentation.
E129 - Fix visual indentation.
E131 - Fix hanging indent for unaligned continuation line.
E133 - Fix missing indentation for closing bracket.
E20 - Remove extraneous whitespace.
E211 - Remove extraneous whitespace.
E22 - Fix extraneous whitespace around keywords.
E224 - Remove extraneous whitespace around operator.
E225 - Fix missing whitespace around operator.
E226 - Fix missing whitespace around arithmetic operator.
E227 - Fix missing whitespace around bitwise/shift operator.
E228 - Fix missing whitespace around modulo operator.
E231 - Add missing whitespace.
E241 - Fix extraneous whitespace around keywords.
E242 - Remove extraneous whitespace around operator.
E251 - Remove whitespace around parameter '=' sign.
E252 - Missing whitespace around parameter equals.
E26 - Fix spacing after comment hash for inline comments.
E265 - Fix spacing after comment hash for block comments.
E266 - Fix too many leading '#' for block comments.
E27 - Fix extraneous whitespace around keywords.
E301 - Add missing blank line.
E302 - Add missing 2 blank lines.
E303 - Remove extra blank lines.
E304 - Remove blank line following function decorator.
E305 - Expected 2 blank lines after end of function or class.
E306 - Expected 1 blank line before a nested definition.
E401 - Put imports on separate lines.
E402 - Fix module level import not at top of file
E501 - Try to make lines fit within --max-line-length characters.
E502 - Remove extraneous escape of newline.
E701 - Put colon-separated compound statement on separate lines.
E70 - Put semicolon-separated compound statement on separate lines.
E711 - Fix comparison with None.
E712 - Fix comparison with boolean.
E713 - Use 'not in' for test for membership.
E714 - Use 'is not' test for object identity.
E721 - Use "isinstance()" instead of comparing types directly.
E722 - Fix bare except.
E731 - Use a def when use do not assign a lambda expression.
W291 - Remove trailing whitespace.
W292 - Add a single newline at the end of the file.
W293 - Remove trailing whitespace on blank line.
W391 - Remove trailing blank lines.
W503 - Fix line break before binary operator.
W504 - Fix line break after binary operator.
W601 - Use "in" rather than "has_key()".
W602 - Fix deprecated form of raising exception.
W603 - Use "!=" instead of "<>"
W604 - Use "repr()" instead of backticks.
W605 - Fix invalid escape sequence 'x'.
W690 - Fix various deprecated code (via lib2to3).

Pycharm 安裝 autopep8

pip 安裝 autopep8: pip install autopep8

PyCharm -> Preferences -> Tools -> Extends Tools -> 點選 + 加號

Name: autopep8

Tools settings:

autopep8
--in-place --aggressive --aggressive $FilePath$
$ProjectFileDir$
$FILE_PATH$:$LINE$:$COLUMN$:.*

Python 之禪

最後以 Python 之禪作為結束語

 [email protected] ~ python3
Python 3.7.1 (default, Nov 6 2018, 18:46:03)
[Clang 10.0.0 (clang-1000.11.45.5)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import this
The Zen of Python, by Tim Peters
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!

翻譯

美 優於 醜

明確 優於 隱晦 (1)

簡單 優於 複雜

複雜 也好過 繁複 (2)

扁平 優於 巢狀

稀疏 優於 擁擠

可讀性很重要(3)

固然程式碼實用與否 比潔癖更重要,

我們以為的特例也往往沒有特殊到必須打破上述規則的程度

除非刻意地靜默,

否則不要無故忽視異常(4)

如果遇到模稜兩可的邏輯,請不要自作聰明地瞎猜。

應該提供一種,且最好只提供一種,一目瞭然的解決方案

當然這是沒法一蹴而就的,除非你是荷蘭人(5)

固然,立刻著手 好過 永遠不做。

然而,永遠不做 也好過 不審慎思考一擼袖子就莽著幹

如果你的實現很難解釋,它就一定不是個好主意

即使你的實現簡單到爆,它也有可能是個好辦法

名稱空間大法好,不搞不是地球人!

註釋

  1. 該引入的包一個一個列出來不要合併;不要用星號;不要在方法裡藏意想不到的的副作用,等等等等。還一個例子,另外一種著名的軟體設計原則 Convention over Configuration(約定優於配置)如果做得不謹慎就會違背這條
  2. SO: 必要的複雜邏輯是難免的,而繁複囉嗦的程式碼是不可接受的
  3. Readability counts 不能翻譯成可讀性計數啊喂
  4. 實操中很多人不注意 catch 完就 log 一下 就不管了,這樣不好。軟體界一般都講 Let it fail,學名為 Fail-fast 法則。簡而言之就是整個專案週期中越早暴露的問題,其修復成本越低
  5. 本文作者 Tim peters 解釋說這裡的荷蘭人指的是 Python 的作者 Guido van Rossum