技術背景
編碼規範是所有程式語言都有可能面臨的問題,嚴格的按照編碼規範來寫程式碼,不僅能夠提高程式碼的可讀性,在後續程式的可維護性上面也有較大的幫助。尤其是在開源專案中,一個具備良好程式設計規範的專案往往能夠吸引更多的開發者一起貢獻。這裡我們介紹2款可以自動幫助我們進行程式碼格式化規範的工具:autopep8以及black的安裝和基本使用方法。
autopep8的安裝
因為都是python寫的規範工具,可以用pip來直接進行版本管理和安裝:
[dechin@dechin-manjaro autopep8]$ python3 -m pip install autopep8
Requirement already satisfied: autopep8 in /home/dechin/anaconda3/lib/python3.8/site-packages (1.5.4)
Requirement already satisfied: toml in /home/dechin/anaconda3/lib/python3.8/site-packages (from autopep8) (0.10.1)
Requirement already satisfied: pycodestyle>=2.6.0 in /home/dechin/anaconda3/lib/python3.8/site-packages (from autopep8) (2.6.0)
安裝完成後,可以使用如下指令測試是否安裝成功:
[dechin@dechin-manjaro autopep8]$ autopep8 --help
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: /home/dechin/.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.
這些彈出的內容,同時也是autopep8的使用框架。
autopep8使用示例
這裡我們使用一個官方提供的案例來進行測試,首先我們看一段非常雜亂的python程式碼,這串程式碼顯然是不符合python編碼規範的:
# example1.py
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)
其中各種函式都被堆到一起,雖然程式碼也能夠正確的執行,但是讓人看了閱讀起來實在是非常費勁,於是我們可以用autopep8這個工具來進行格式化處理:
[dechin@dechin-manjaro autopep8]$ autopep8 --in-place --aggressive --aggressive example1.py
執行完上述指令後,我們再來看看剛才的程式碼檔案:
# example1.py
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也並不能一次性解決所有的PEP8規範中的問題,比如以下的一個案例:
[dechin@dechin-manjaro autopep8]$ cat example2.py
# example2.py
print ("sjalfjlsa kkajslajs ls dlaj la jsk dka jdla kjdlksa jd alsk jdlka jsdlak jlksa jla dasajdk la jk das dada sa.")
(base) [dechin@dechin-manjaro autopep8]$ autopep8 --in-place -a -a example2.py
(base) [dechin@dechin-manjaro autopep8]$ cat example2.py
# example2.py
print("sjalfjlsa kkajslajs ls dlaj la jsk dka jdla kjdlksa jd alsk jdlka jsdlak jlksa jla dasajdk la jk das dada sa.")
在這個案例中,我們給出了一個程式碼行長度超過規範要求的例子,但是用autopep8處理之後,程式碼並沒有被改變,如果此時用flake8來進行檢測,還是能夠檢查出程式碼超長的問題:
[dechin@dechin-manjaro autopep8]$ flake8
./example2.py:4:80: E501 line too long (115 > 79 characters)
因此這些自動規範化處理的工具畢竟是機器處理,要想真正的達到規範要求,我們最好還是自動規範化的工具結合規範檢查的工具,再配合人工的修改,這樣才能夠寫出質量更高的程式碼。
black工具的安裝
除了autopep8之外,還有另外一款也非常常用的自動化規範工具:black,這裡我們就不展開介紹其使用方法,僅介紹安裝的過程及其官方的幫助文件:
[dechin@dechin-manjaro autopep8]$ python3 -m pip install black -i https://mirrors.cloud.tencent.com/pypi/simple
Looking in indexes: https://mirrors.cloud.tencent.com/pypi/simple
Collecting black
Downloading https://mirrors.cloud.tencent.com/pypi/packages/dc/7b/5a6bbe89de849f28d7c109f5ea87b65afa5124ad615f3419e71beb29dc96/black-20.8b1.tar.gz (1.1 MB)
|████████████████████████████████| 1.1 MB 724 kB/s
Installing build dependencies ... done
Getting requirements to build wheel ... done
Preparing wheel metadata ... done
Requirement already satisfied: regex>=2020.1.8 in /home/dechin/anaconda3/lib/python3.8/site-packages (from black) (2020.10.15)
Requirement already satisfied: typing-extensions>=3.7.4 in /home/dechin/anaconda3/lib/python3.8/site-packages (from black) (3.7.4.3)
Requirement already satisfied: click>=7.1.2 in /home/dechin/anaconda3/lib/python3.8/site-packages (from black) (7.1.2)
Collecting pathspec<1,>=0.6
Downloading https://mirrors.cloud.tencent.com/pypi/packages/29/29/a465741a3d97ea3c17d21eaad4c64205428bde56742360876c4391f930d4/pathspec-0.8.1-py2.py3-none-any.whl (28 kB)
Collecting typed-ast>=1.4.0
Downloading https://mirrors.cloud.tencent.com/pypi/packages/0d/14/d54fd856673e3a5cb230e481bcdea04976c28b691a65029a7d45aef80575/typed_ast-1.4.3-cp38-cp38-manylinux1_x86_64.whl (774 kB)
|████████████████████████████████| 774 kB 939 kB/s
Requirement already satisfied: toml>=0.10.1 in /home/dechin/anaconda3/lib/python3.8/site-packages (from black) (0.10.1)
Collecting mypy-extensions>=0.4.3
Downloading https://mirrors.cloud.tencent.com/pypi/packages/5c/eb/975c7c080f3223a5cdaff09612f3a5221e4ba534f7039db34c35d95fa6a5/mypy_extensions-0.4.3-py2.py3-none-any.whl (4.5 kB)
Requirement already satisfied: appdirs in /home/dechin/anaconda3/lib/python3.8/site-packages (from black) (1.4.4)
Building wheels for collected packages: black
Building wheel for black (PEP 517) ... done
Created wheel for black: filename=black-20.8b1-py3-none-any.whl size=124184 sha256=2a1cde43fd729754692b801426aa8cd0becaabe73ae989f6caa761bac46ca9de
Stored in directory: /home/dechin/.cache/pip/wheels/b5/b8/0f/2d0f8b6f216e8a42f90dcc4d960f30dbf8d5e08dc1b034b32c
Successfully built black
Installing collected packages: pathspec, typed-ast, mypy-extensions, black
Successfully installed black-20.8b1 mypy-extensions-0.4.3 pathspec-0.8.1 typed-ast-1.4.3
同樣的也是使用pip來進行包的安裝和管理,然後可以在命令列執行black --help
檢視幫助文件,整體而言跟autopep8還是非常類似的。
[dechin@dechin-manjaro autopep8]$ black --help
Usage: black [OPTIONS] [SRC]...
The uncompromising code formatter.
Options:
-c, --code TEXT Format the code passed in as a string.
-l, --line-length INTEGER How many characters per line to allow.
[default: 88]
-t, --target-version [py27|py33|py34|py35|py36|py37|py38]
Python versions that should be supported by
Black's output. [default: per-file auto-
detection]
--pyi Format all input files like typing stubs
regardless of file extension (useful when
piping source on standard input).
-S, --skip-string-normalization
Don't normalize string quotes or prefixes.
--check Don't write the files back, just return the
status. Return code 0 means nothing would
change. Return code 1 means some files
would be reformatted. Return code 123 means
there was an internal error.
--diff Don't write the files back, just output a
diff for each file on stdout.
--color / --no-color Show colored diff. Only applies when
`--diff` is given.
--fast / --safe If --fast given, skip temporary sanity
checks. [default: --safe]
--include TEXT A regular expression that matches files and
directories that should be included on
recursive searches. An empty value means
all files are included regardless of the
name. Use forward slashes for directories
on all platforms (Windows, too). Exclusions
are calculated first, inclusions later.
[default: \.pyi?$]
--exclude TEXT A regular expression that matches files and
directories that should be excluded on
recursive searches. An empty value means no
paths are excluded. Use forward slashes for
directories on all platforms (Windows, too).
Exclusions are calculated first, inclusions
later. [default: /(\.direnv|\.eggs|\.git|\.
hg|\.mypy_cache|\.nox|\.tox|\.venv|\.svn|_bu
ild|buck-out|build|dist)/]
--force-exclude TEXT Like --exclude, but files and directories
matching this regex will be excluded even
when they are passed explicitly as arguments
-q, --quiet Don't emit non-error messages to stderr.
Errors are still emitted; silence those with
2>/dev/null.
-v, --verbose Also emit messages to stderr about files
that were not changed or were ignored due to
--exclude=.
--version Show the version and exit.
--config FILE Read configuration from FILE path.
-h, --help Show this message and exit.
總結概要
本文主要通過介紹兩個python中常用的編碼規範格式化工具:autopep8和black來講解python程式設計中一些快速處理程式設計規範問題的方法,同時也說明了這些軟體的侷限性。程式設計規範也是人為制定的,事實上在實際專案中,也不是所有的程式設計規範都需要滿足,這就需要專案的組織者或者領導者有自己的基本判斷。結合程式碼規範檢查工具flake8以及文章中介紹的這些程式碼規範格式化工具,最重要的還是要配合以人的判斷和調整,才能使得專案具有更好的可讀性、可維護性以及更友善的生態。
版權宣告
本文首發連結為:https://www.cnblogs.com/dechinphy/p/formater.html
作者ID:DechinPhy
更多原著文章請參考:https://www.cnblogs.com/dechinphy/
打賞專用連結:https://www.cnblogs.com/dechinphy/gallery/image/379634.html
騰訊雲專欄同步:https://cloud.tencent.com/developer/column/91958