YAPF เป็นตัวจัดรูปแบบ Python ที่ใช้ clang-format
(พัฒนาโดย Daniel Jasper) โดยพื้นฐานแล้ว อัลกอริธึมจะใช้โค้ดและคำนวณการจัดรูปแบบที่ดีที่สุดซึ่งสอดคล้องกับสไตล์ที่กำหนดค่าไว้ จะช่วยขจัดความน่าเบื่อหน่ายมากมายในการดูแลรักษาโค้ดของคุณ
เป้าหมายสูงสุดคือโค้ดที่ YAPF สร้างขึ้นนั้นดีพอๆ กับโค้ดที่โปรแกรมเมอร์จะเขียนหากพวกเขาทำตามคำแนะนำสไตล์
หมายเหตุ YAPF ไม่ใช่ผลิตภัณฑ์อย่างเป็นทางการของ Google (ทดลองหรืออย่างอื่น) เป็นเพียงโค้ดที่ Google เป็นเจ้าของ
วิธีติดตั้ง YAPF จาก PyPI:
$ pip install yapf
YAPF ยังถือว่าอยู่ในระยะ "เบต้า" และเวอร์ชันที่เผยแพร่อาจมีการเปลี่ยนแปลงบ่อยครั้ง ดังนั้นวิธีที่ดีที่สุดในการติดตามการพัฒนาล่าสุดคือการโคลนพื้นที่เก็บข้อมูลนี้หรือติดตั้งโดยตรงจาก GitHub:
$ pip install git+https://github.com/google/yapf.git
โปรดทราบว่าหากคุณต้องการใช้ YAPF เป็นเครื่องมือบรรทัดคำสั่งแทนที่จะเป็นไลบรารี การติดตั้งก็ไม่จำเป็น YAPF รองรับการรันเป็นไดเร็กทอรีโดยล่าม Python หากคุณโคลน/แตกไฟล์ YAPF ลงใน DIR
ก็เป็นไปได้ที่จะเรียกใช้:
$ PYTHONPATH=DIR python DIR/yapf [options] ...
YAPF ได้รับการสนับสนุนจากบรรณาธิการหลายคนผ่านทางส่วนขยายหรือปลั๊กอินของชุมชน ดูการสนับสนุนตัวแก้ไขสำหรับข้อมูลเพิ่มเติม
YAPF รองรับ Python 3.7+
usage: yapf [-h] [-v] [-d | -i | -q] [-r | -l START-END] [-e PATTERN]
[--style STYLE] [--style-help] [--no-local-style] [-p] [-m] [-vv]
[files ...]
Formatter for Python code.
positional arguments:
files reads from stdin when no files are specified.
optional arguments:
-h, --help show this help message and exit
-v, --version show program's version number and exit
-d, --diff print the diff for the fixed source
-i, --in-place make changes to files in place
-q, --quiet output nothing and set return value
-r, --recursive run recursively over directories
-l START-END, --lines START-END
range of lines to reformat, one-based
-e PATTERN, --exclude PATTERN
patterns for files to exclude from formatting
--style STYLE specify formatting style: either a style name (for
example "pep8" or "google"), or the name of a file
with style settings. The default is pep8 unless a
.style.yapf or setup.cfg or pyproject.toml file
located in the same directory as the source or one of
its parent directories (for stdin, the current
directory is used).
--style-help show style settings and exit; this output can be saved
to .style.yapf to make your settings permanent
--no-local-style don't search for local style definition
-p, --parallel run YAPF in parallel when formatting multiple files.
-m, --print-modified print out file names of modified files
-vv, --verbose print out file names while processing
โดยปกติ YAPF จะส่งกลับค่าศูนย์เมื่อยุติโปรแกรมสำเร็จ และหากไม่เป็นเช่นนั้นจะส่งกลับค่าศูนย์
หากระบุ --diff
ไว้ YAPF จะส่งกลับค่าศูนย์เมื่อไม่จำเป็นต้องทำการเปลี่ยนแปลง หรือมิฉะนั้นจะไม่ใช่ศูนย์ (รวมถึงข้อผิดพลาดของโปรแกรมด้วย) คุณสามารถใช้สิ่งนี้ในเวิร์กโฟลว์ CI เพื่อทดสอบว่าโค้ดนั้นมีรูปแบบ YAPF
นอกเหนือจากการแยกรูปแบบที่มีให้บนบรรทัดคำสั่งแล้ว YAPF ยังค้นหารูปแบบเพิ่มเติมที่ระบุในไฟล์ชื่อ .yapfignore
หรือ pyproject.toml
ที่อยู่ในไดเร็กทอรีการทำงานที่มีการเรียกใช้ YAPF
ไวยากรณ์ของ .yapfignore
คล้ายกับการจับคู่รูปแบบชื่อไฟล์ของ UNIX:
* matches everything
? matches any single character
[seq] matches any character in seq
[!seq] matches any character not in seq
โปรดทราบว่าไม่ควรมีรายการขึ้นต้นด้วย ./
หากคุณใช้ pyproject.toml
รูปแบบที่ยกเว้นจะถูกระบุโดยปุ่ม ignore_patterns
ในส่วน [tool.yapfignore]
ตัวอย่างเช่น:
[tool.yapfignore]
ignore_patterns = [
" temp/**/*.py " ,
" temp2/*.py "
]
สไตล์การจัดรูปแบบที่ใช้โดย YAPF นั้นสามารถกำหนดค่าได้ และมี "ปุ่ม" มากมายที่สามารถใช้เพื่อปรับแต่งวิธีการจัดรูปแบบ YAPF ดูโมดูล style.py
สำหรับรายการทั้งหมด
หากต้องการควบคุมสไตล์ ให้รัน YAPF ด้วยอาร์กิวเมนต์ --style
ยอมรับหนึ่งในสไตล์ที่กำหนดไว้ล่วงหน้า (เช่น pep8
หรือ google
) เส้นทางไปยังไฟล์การกำหนดค่าที่ระบุสไตล์ที่ต้องการ หรือพจนานุกรมของคู่คีย์/ค่า
ไฟล์กำหนดค่าเป็นรายการอย่างง่ายของ key = value
(ไม่คำนึงถึงตัวพิมพ์เล็กและตัวพิมพ์ใหญ่) พร้อมส่วนหัว [style]
ตัวอย่างเช่น:
[style]
based_on_style = pep8
spaces_before_comment = 4
split_before_logical_operator = true
การตั้งค่า based_on_style
จะกำหนดสไตล์ที่กำหนดไว้ล่วงหน้าซึ่งสไตล์ที่กำหนดเองนี้จะขึ้นอยู่กับ (คิดว่าเหมือนกับคลาสย่อย) มีการกำหนดไว้ล่วงหน้าสี่สไตล์:
pep8
(ค่าเริ่มต้น)google
(อ้างอิงจากคู่มือสไตล์ Google Python)yapf
(สำหรับใช้กับโครงการโอเพ่นซอร์สของ Google)facebook
ดู _STYLE_NAME_TO_FACTORY
ใน style.py
เพื่อดูรายละเอียด
นอกจากนี้ยังเป็นไปได้ที่จะทำเช่นเดียวกันบนบรรทัดคำสั่งด้วยพจนานุกรม ตัวอย่างเช่น:
--style= ' {based_on_style: pep8, indent_width: 2} '
การดำเนินการนี้จะใช้รูปแบบฐาน pep8
และแก้ไขให้มีช่องว่าง 2 ช่อง
YAPF จะค้นหาสไตล์การจัดรูปแบบในลักษณะต่อไปนี้:
[style]
ของไฟล์ .style.yapf
ในไดเร็กทอรีปัจจุบันหรือไดเร็กทอรีหลักอย่างใดอย่างหนึ่ง[yapf]
ของไฟล์ setup.cfg
ในไดเร็กทอรีปัจจุบันหรือไดเร็กทอรีหลักอย่างใดอย่างหนึ่ง[tool.yapf]
ของไฟล์ pyproject.toml
ในไดเร็กทอรีปัจจุบันหรือไดเร็กทอรีหลักอย่างใดอย่างหนึ่ง[style]
ของ ~/.config/yapf/style
ไฟล์ในโฮมไดเร็กตอรี่ของคุณหากไม่พบไฟล์เหล่านั้น ระบบจะใช้สไตล์เริ่มต้น PEP8
ตัวอย่างการจัดรูปแบบประเภทที่ YAPF สามารถทำได้ โดยจะใช้โค้ดที่น่าเกลียดนี้:
x = { 'a' : 37 , 'b' : 42 ,
'c' : 927 }
y = 'hello ' 'world'
z = 'hello ' + 'world'
a = 'hello {}' . format ( 'world' )
class foo ( object ):
def f ( self ):
return 37 * - + 2
def g ( self , x , y = 42 ):
return y
def f ( a ) :
return 37 + - + a [ 42 - x : y ** 3 ]
และฟอร์แมตใหม่เป็น:
x = { 'a' : 37 , 'b' : 42 , 'c' : 927 }
y = 'hello ' 'world'
z = 'hello ' + 'world'
a = 'hello {}' . format ( 'world' )
class foo ( object ):
def f ( self ):
return 37 * - + 2
def g ( self , x , y = 42 ):
return y
def f ( a ):
return 37 + - + a [ 42 - x : y ** 3 ]
API หลักสองตัวสำหรับการเรียก YAPF คือ FormatCode
และ FormatFile
ซึ่งใช้อาร์กิวเมนต์ร่วมกันหลายข้อซึ่งอธิบายไว้ด้านล่าง:
> >> from yapf . yapflib . yapf_api import FormatCode # reformat a string of code
> >> formatted_code , changed = FormatCode ( "f ( a = 1, b = 2 )" )
> >> formatted_code
'f(a=1, b=2) n '
> >> changed
True
อาร์กิวเมนต์ style_config
: ชื่อสไตล์หรือเส้นทางไปยังไฟล์ที่มีการตั้งค่ารูปแบบการจัดรูปแบบ หากระบุไม่มี ให้ใช้สไตล์เริ่มต้นตามที่ตั้งค่าไว้ใน style.DEFAULT_STYLE_FACTORY
> >> FormatCode ( "def g(): n return True" , style_config = 'pep8' )[ 0 ]
'def g(): n return True n '
อาร์กิวเมนต์ lines
: รายการสิ่งอันดับของบรรทัด (ints), [เริ่มต้น, สิ้นสุด] ที่เราต้องการจัดรูปแบบ เส้นมีการจัดทำดัชนีแบบ 1 สามารถใช้โดยโค้ดของบุคคลที่สาม (เช่น IDE) เมื่อฟอร์แมตข้อมูลโค้ดแทนการฟอร์แมตไฟล์ทั้งหมด
> >> FormatCode ( "def g( ): n a=1 n b = 2 n return a==b" , lines = [( 1 , 1 ), ( 2 , 3 )])[ 0 ]
'def g(): n a = 1 n b = 2 n return a==b n '
print_diff
(bool): แทนที่จะส่งคืนแหล่งที่ฟอร์แมตแล้ว ให้ส่งคืนส่วนต่างที่เปลี่ยนแหล่งที่จัดรูปแบบแล้วให้กลายเป็นแหล่งที่จัดรูปแบบใหม่
>>> print(FormatCode("a==b", filename="foo.py", print_diff=True)[0])
--- foo.py (original)
+++ foo.py (reformatted)
@@ -1 +1 @@
- a==b
+ a == b
หมายเหตุ: อาร์กิวเมนต์ filename
สำหรับ FormatCode
คือสิ่งที่แทรกลงในส่วนต่าง โดยค่าเริ่มต้นคือ <unknown>
FormatFile
ส่งคืนโค้ดที่จัดรูปแบบใหม่จากไฟล์ที่ส่งผ่านพร้อมกับการเข้ารหัส:
> >> from yapf . yapflib . yapf_api import FormatFile # reformat a file
> >> print ( open ( "foo.py" ). read ()) # contents of file
a == b
> >> reformatted_code , encoding , changed = FormatFile ( "foo.py" )
> >> formatted_code
'a == b n '
> >> encoding
'utf-8'
> >> changed
True
อาร์กิวเมนต์ in_place
จะบันทึกโค้ดที่จัดรูปแบบใหม่กลับไปยังไฟล์:
> >> FormatFile ( "foo.py" , in_place = True )[: 2 ]
( None , 'utf-8' )
> >> print ( open ( "foo.py" ). read ()) # contents of file (now fixed)
a == b
ตัวเลือก:
usage: yapf-diff [-h] [-i] [-p NUM] [--regex PATTERN] [--iregex PATTERN][-v]
[--style STYLE] [--binary BINARY]
This script reads input from a unified diff and reformats all the changed
lines. This is useful to reformat all the lines touched by a specific patch.
Example usage for git/svn users:
git diff -U0 --no-color --relative HEAD^ | yapf-diff -i
svn diff --diff-cmd=diff -x-U0 | yapf-diff -p0 -i
It should be noted that the filename contained in the diff is used
unmodified to determine the source file to update. Users calling this script
directly should be careful to ensure that the path in the diff is correct
relative to the current working directory.
optional arguments:
-h, --help show this help message and exit
-i, --in-place apply edits to files instead of displaying a diff
-p NUM, --prefix NUM strip the smallest prefix containing P slashes
--regex PATTERN custom pattern selecting file paths to reformat
(case sensitive, overrides -iregex)
--iregex PATTERN custom pattern selecting file paths to reformat
(case insensitive, overridden by -regex)
-v, --verbose be more verbose, ineffective without -i
--style STYLE specify formatting style: either a style name (for
example "pep8" or "google"), or the name of a file
with style settings. The default is pep8 unless a
.style.yapf or setup.cfg or pyproject.toml file
located in the same directory as the source or one of
its parent directories (for stdin, the current
directory is used).
--binary BINARY location of binary to use for YAPF
ALIGN_CLOSING_BRACKET_WITH_VISUAL_INDENT
จัดวงเล็บปิดให้ตรงกับการเยื้องแบบมองเห็น
ALLOW_MULTILINE_LAMBDAS
อนุญาตให้จัดรูปแบบ lambdas มากกว่า 1 บรรทัด
ALLOW_MULTILINE_DICTIONARY_KEYS
อนุญาตให้มีคีย์พจนานุกรมอยู่ในหลายบรรทัด ตัวอย่างเช่น:
x = {
( 'this is the first element of a tuple' ,
'this is the second element of a tuple' ):
value ,
}
ALLOW_SPLIT_BEFORE_DEFAULT_OR_NAMED_ASSIGNS
อนุญาตให้แยกก่อนการกำหนดค่าเริ่มต้น / ตั้งชื่อในรายการอาร์กิวเมนต์
ALLOW_SPLIT_BEFORE_DICT_VALUE
อนุญาตให้แยกก่อนค่าพจนานุกรม
ARITHMETIC_PRECEDENCE_INDICATION
ให้ระยะห่างบ่งชี้ลำดับความสำคัญของตัวดำเนินการ ตัวอย่างเช่น:
a = 1 * 2 + 3 / 4
b = 1 / 2 - 3 * 4
c = ( 1 + 2 ) * ( 3 - 4 )
d = ( 1 - 2 ) / ( 3 + 4 )
e = 1 * 2 - 3
f = 1 + 2 + 3 + 4
จะถูกจัดรูปแบบดังต่อไปนี้เพื่อระบุลำดับความสำคัญ:
a = 1 * 2 + 3 / 4
b = 1 / 2 - 3 * 4
c = ( 1 + 2 ) * ( 3 - 4 )
d = ( 1 - 2 ) / ( 3 + 4 )
e = 1 * 2 - 3
f = 1 + 2 + 3 + 4
BLANK_LINES_AROUND_TOP_LEVEL_DEFINITION
ตั้งค่าจำนวนบรรทัดว่างที่ต้องการรอบๆ ฟังก์ชันระดับบนสุดและคำจำกัดความของคลาส ตัวอย่างเช่น:
class Foo :
pass
# <------ having two blank lines here
# <------ is the default setting
class Bar :
pass
BLANK_LINE_BEFORE_CLASS_DOCSTRING
แทรกบรรทัดว่างก่อนสตริงเอกสารระดับชั้นเรียน
BLANK_LINE_BEFORE_MODULE_DOCSTRING
แทรกบรรทัดว่างก่อนสตริงเอกสารของโมดูล
BLANK_LINE_BEFORE_NESTED_CLASS_OR_DEF
แทรกบรรทัดว่างก่อน
def
หรือclass
ที่ซ้อนอยู่ในdef
หรือclass
อื่นทันที ตัวอย่างเช่น:
class Foo :
# <------ this blank line
def method ():
pass
BLANK_LINES_BETWEEN_TOP_LEVEL_IMPORTS_AND_VARIABLES
ตั้งค่าจำนวนบรรทัดว่างที่ต้องการระหว่างการนำเข้าระดับบนสุดและคำจำกัดความของตัวแปร มีประโยชน์สำหรับการใช้งานร่วมกับเครื่องมือเช่น isort
COALESCE_BRACKETS
อย่าแยกวงเล็บที่ติดกัน เกี่ยวข้องเฉพาะเมื่อมีการตั้งค่า
DEDENT_CLOSING_BRACKETS
หรือINDENT_CLOSING_BRACKETS
ตัวอย่างเช่น:
call_func_that_takes_a_dict (
{
'key1' : 'value1' ,
'key2' : 'value2' ,
}
)
จะฟอร์แมตเป็น:
call_func_that_takes_a_dict ({
'key1' : 'value1' ,
'key2' : 'value2' ,
})
COLUMN_LIMIT
ขีดจำกัดของคอลัมน์ (หรือความยาวบรรทัดสูงสุด)
CONTINUATION_ALIGN_STYLE
รูปแบบการจัดแนวต่อเนื่อง ค่าที่เป็นไปได้คือ:
SPACE
: ใช้ช่องว่างเพื่อจัดแนวต่อเนื่อง นี่เป็นพฤติกรรมเริ่มต้นFIXED
: ใช้หมายเลขคงที่ (CONTINUATION_INDENT_WIDTH
) ของคอลัมน์ (เช่น แท็บCONTINUATION_INDENT_WIDTH
/INDENT_WIDTH
หรือช่องว่างCONTINUATION_INDENT_WIDTH
) สำหรับการจัดตำแหน่งต่อเนื่องVALIGN-RIGHT
: จัดแนวบรรทัดต่อเนื่องในแนวตั้งกับหลายคอลัมน์INDENT_WIDTH
ไปทางขวาเล็กน้อย (หนึ่งแท็บหรือสองสามช่องว่าง) หากไม่สามารถจัดแนวต่อเนื่องในแนวตั้งด้วยอักขระเยื้องได้
CONTINUATION_INDENT_WIDTH
ความกว้างเยื้องที่ใช้สำหรับการต่อเนื่องของบรรทัด
DEDENT_CLOSING_BRACKETS
ใส่วงเล็บปิดในบรรทัดแยกกัน โดยเว้นไว้ หากนิพจน์ในวงเล็บไม่สามารถบรรจุลงในบรรทัดเดียวได้ ใช้กับวงเล็บทุกประเภท รวมถึงคำจำกัดความของฟังก์ชันและการเรียกใช้ ตัวอย่างเช่น:
config = {
'key1' : 'value1' ,
'key2' : 'value2' ,
} # <--- this bracket is dedented and on a separate line
time_series = self . remote_client . query_entity_counters (
entity = 'dev3246.region1' ,
key = 'dns.query_latency_tcp' ,
transform = Transformation . AVERAGE ( window = timedelta ( seconds = 60 )),
start_ts = now () - timedelta ( days = 3 ),
end_ts = now (),
) # <--- this bracket is dedented and on a separate line
DISABLE_ENDING_COMMA_HEURISTIC
ปิดใช้งานการศึกษาพฤติกรรมซึ่งจะวางแต่ละองค์ประกอบรายการในบรรทัดแยกกันหากรายการถูกยกเลิกด้วยเครื่องหมายจุลภาค
หมายเหตุ: พฤติกรรมของแฟล็กนี้เปลี่ยนไปในเวอร์ชัน 0.40.3 ก่อนหน้านี้ หากแฟล็กนี้เป็นจริง เราจะแยกรายการที่มีเครื่องหมายจุลภาคหรือความคิดเห็นต่อท้าย ตอนนี้ เรามีแฟล็กแยกต่างหาก
DISABLE_SPLIT_LIST_WITH_COMMENT
ซึ่งควบคุมการแยกเมื่อรายการมีความคิดเห็น หากต้องการรับลักษณะการทำงานแบบเก่า ให้ตั้งค่าสถานะทั้งสองเป็นจริง ข้อมูลเพิ่มเติมใน CHANGELOG.md
DISABLE_SPLIT_LIST_WITH_COMMENT
อย่าใส่ทุกองค์ประกอบในบรรทัดใหม่ภายในรายการที่มีความคิดเห็นคั่นระหว่างหน้า
หากไม่มีแฟล็กนี้ (ค่าเริ่มต้น):
[ a, b, # c ]
ด้วยธงนี้:
[ a, b, # c ]
สิ่งนี้สะท้อนพฤติกรรมของรูปแบบเสียงดังกราวและมีประโยชน์สำหรับการสร้าง "กลุ่มเชิงตรรกะ" ขององค์ประกอบในรายการ มันยังใช้งานได้ในการประกาศฟังก์ชันด้วย
EACH_DICT_ENTRY_ON_SEPARATE_LINE
วางรายการพจนานุกรมแต่ละรายการไว้ในบรรทัดของตัวเอง
FORCE_MULTILINE_DICT
เคารพ
EACH_DICT_ENTRY_ON_SEPARATE_LINE
แม้ว่าบรรทัดจะสั้นกว่าCOLUMN_LIMIT
I18N_COMMENT
Regex สำหรับความคิดเห็นที่เป็นสากล การมีอยู่ของความคิดเห็นนี้จะหยุดการจัดรูปแบบใหม่ของบรรทัดนั้น เนื่องจากความคิดเห็นจะต้องอยู่ถัดจากสตริงที่แปล
I18N_FUNCTION_CALL
ชื่อการเรียกฟังก์ชันสากล การมีอยู่ของฟังก์ชันนี้จะหยุดการจัดรูปแบบใหม่บนบรรทัดนั้น เนื่องจากสตริงที่มีอยู่ไม่สามารถย้ายออกจากความคิดเห็น i18n ได้
INDENT_BLANK_LINES
ตั้งค่าเป็น
True
เพื่อต้องการใช้บรรทัดว่างเยื้องมากกว่าว่างเปล่า
INDENT_CLOSING_BRACKETS
ใส่วงเล็บปิดในบรรทัดแยกกัน โดยเยื้องไว้ ถ้านิพจน์ในวงเล็บไม่สามารถบรรจุลงในบรรทัดเดียวได้ ใช้กับวงเล็บทุกประเภท รวมถึงคำจำกัดความของฟังก์ชันและการเรียกใช้ ตัวอย่างเช่น:
config = {
'key1' : 'value1' ,
'key2' : 'value2' ,
} # <--- this bracket is indented and on a separate line
time_series = self . remote_client . query_entity_counters (
entity = 'dev3246.region1' ,
key = 'dns.query_latency_tcp' ,
transform = Transformation . AVERAGE ( window = timedelta ( seconds = 60 )),
start_ts = now () - timedelta ( days = 3 ),
end_ts = now (),
) # <--- this bracket is indented and on a separate line
INDENT_DICTIONARY_VALUE
เยื้องค่าพจนานุกรมหากไม่สามารถให้พอดีกับบรรทัดเดียวกับคีย์พจนานุกรมได้ ตัวอย่างเช่น:
config = {
'key1' :
'value1' ,
'key2' : value1 +
value2 ,
}
INDENT_WIDTH
จำนวนคอลัมน์ที่จะใช้สำหรับการเยื้อง
JOIN_MULTIPLE_LINES
รวมบรรทัดสั้น ๆ ให้เป็นหนึ่งบรรทัด เช่น คำสั่ง
if
บรรทัดเดียว
NO_SPACES_AROUND_SELECTED_BINARY_OPERATORS
อย่าเว้นวรรครอบตัวดำเนินการไบนารีที่เลือก ตัวอย่างเช่น:
1 + 2 * 3 - 4 / 5
จะถูกจัดรูปแบบดังนี้เมื่อกำหนดค่าด้วย
*
,/
:
1 + 2 * 3 - 4 / 5
SPACE_BETWEEN_ENDING_COMMA_AND_CLOSING_BRACKET
แทรกช่องว่างระหว่างเครื่องหมายจุลภาคปิดและวงเล็บปิดของรายการ ฯลฯ
SPACE_INSIDE_BRACKETS
Use spaces inside brackets, braces, and parentheses. For example:
method_call ( 1 )
my_dict [ 3 ][ 1 ][ get_index ( * args , ** kwargs ) ]
my_set = { 1 , 2 , 3 }
SPACES_AROUND_DEFAULT_OR_NAMED_ASSIGN
ตั้งค่าเป็น
True
เพื่อใช้ช่องว่างรอบๆ ตัวดำเนินการที่ได้รับมอบหมายสำหรับอาร์กิวเมนต์เริ่มต้นหรือคำสำคัญ
SPACES_AROUND_DICT_DELIMITERS
เพิ่มช่องว่างหลังตัวคั่น dict เปิด '{' และก่อนจุดสิ้นสุด '}'
{ 1 : 2 }
จะถูกจัดรูปแบบเป็น:
{ 1 : 2 }
SPACES_AROUND_LIST_DELIMITERS
เพิ่มช่องว่างหลังตัวคั่นรายการเปิด '[' และก่อนตัวคั่นรายการ ']'
[ 1 , 2 ]
จะถูกจัดรูปแบบเป็น:
[ 1 , 2 ]
SPACES_AROUND_POWER_OPERATOR
ตั้งค่าเป็น
True
เพื่อใช้ช่องว่างรอบๆ**
SPACES_AROUND_SUBSCRIPT_COLON
ใช้ช่องว่างรอบตัวดำเนินการตัวห้อย / ชิ้น ตัวอย่างเช่น:
my_list [ 1 : 10 : 2 ]
SPACES_AROUND_TUPLE_DELIMITERS
เพิ่มช่องว่างหลังตัวคั่นทูเพิลเปิด '(' และก่อนจุดสิ้นสุด ')'
( 1 , 2 , 3 )
จะถูกจัดรูปแบบเป็น:
( 1 , 2 , 3 )
SPACES_BEFORE_COMMENT
จำนวนช่องว่างที่ต้องการก่อนความคิดเห็นต่อท้าย ซึ่งอาจเป็นค่าเดียว (แสดงถึงจำนวนช่องว่างก่อนความคิดเห็นต่อท้ายแต่ละความคิดเห็น) หรือรายการค่า (แสดงถึงค่าคอลัมน์การจัดตำแหน่ง ความคิดเห็นต่อท้ายภายในบล็อกจะถูกจัดให้สอดคล้องกับค่าคอลัมน์แรกที่มากกว่าความยาวบรรทัดสูงสุดภายใน ปิดกั้น).
หมายเหตุ: รายการค่าอาจต้องมีการอ้างอิงในบางบริบท (เช่น เชลล์หรือไฟล์กำหนดค่าของตัวแก้ไข)
ตัวอย่างเช่น ด้วย
spaces_before_comment=5
:
1 + 1 # Adding values
จะถูกจัดรูปแบบเป็น:
1 + 1 # Adding values <-- 5 spaces between the end of the statement and comment
ด้วย
spaces_before_comment="15, 20"
:
1 + 1 # Adding values
two + two # More adding
longer_statement # This is a longer statement
short # This is a shorter statement
a_very_long_statement_that_extends_beyond_the_final_column # Comment
short # This is a shorter statement
จะถูกจัดรูปแบบเป็น:
1 + 1 # Adding values <-- end of line comments in block aligned to col 15
two + two # More adding
longer_statement # This is a longer statement <-- end of line comments in block aligned to col 20
short # This is a shorter statement
a_very_long_statement_that_extends_beyond_the_final_column # Comment <-- the end of line comments are aligned based on the line length
short # This is a shorter statement
SPLIT_ALL_COMMA_SEPARATED_VALUES
หากรายการที่คั่นด้วยเครื่องหมายจุลภาค (
dict
,list
,tuple
หรือ functiondef
) อยู่บนบรรทัดที่ยาวเกินไป ให้แยกแต่ละองค์ประกอบให้แยกบรรทัดกัน
SPLIT_ALL_TOP_LEVEL_COMMA_SEPARATED_VALUES
การเปลี่ยนแปลงของ
SPLIT_ALL_COMMA_SEPARATED_VALUES
ซึ่งหากนิพจน์ย่อยที่มีเครื่องหมายจุลภาคพอดีกับบรรทัดเริ่มต้น นิพจน์ย่อยจะไม่ถูกแยก วิธีนี้จะหลีกเลี่ยงการแยกเหมือนการแยกb
ในโค้ดนี้:
abcdef (
aReallyLongThing : int ,
b : [ Int ,
Int ])
ด้วยลูกบิดใหม่สิ่งนี้จะแบ่งออกเป็น:
abcdef (
aReallyLongThing : int ,
b : [ Int , Int ])
SPLIT_ARGUMENTS_WHEN_COMMA_TERMINATED
แยกก่อนอาร์กิวเมนต์หากรายการอาร์กิวเมนต์ถูกยกเลิกด้วยเครื่องหมายจุลภาค
SPLIT_BEFORE_ARITHMETIC_OPERATOR
ตั้งค่าเป็น
True
เพื่อต้องการแยกก่อน+
,-
,*
,/
,//
หรือ@
แทนที่จะเป็นหลัง
SPLIT_BEFORE_BITWISE_OPERATOR
ตั้งค่าเป็น
True
เพื่อต้องการแยกก่อน&
,|
หรือ^
แทนที่จะเป็นหลัง
SPLIT_BEFORE_CLOSING_BRACKET
แยกก่อนวงเล็บปิดหาก
list
หรือตัวอักษรdict
ไม่พอดีกับบรรทัดเดียว
SPLIT_BEFORE_DICT_SET_GENERATOR
แยกหน้าพจนานุกรมหรือตั้งค่าตัวสร้าง (
comp_for
) ตัวอย่างเช่น สังเกตการแยกก่อนfor
:
foo = {
variable : 'Hello world, have a nice day!'
for variable in bar if variable != 42
}
SPLIT_BEFORE_DOT
แยกกันก่อน
.
หากเราต้องแยกนิพจน์ที่ยาวกว่านี้:
foo = ( 'This is a really long string: {}, {}, {}, {}' . format ( a , b , c , d ))
จะฟอร์แมตใหม่เป็นดังนี้:
foo = ( 'This is a really long string: {}, {}, {}, {}'
. format ( a , b , c , d ))
SPLIT_BEFORE_EXPRESSION_AFTER_OPENING_PAREN
แยกหลังวงเล็บเปิดซึ่งล้อมรอบนิพจน์หากไม่พอดีกับบรรทัดเดียว
SPLIT_BEFORE_FIRST_ARGUMENT
หากรายการอาร์กิวเมนต์ / พารามิเตอร์จะถูกแยก ให้แยกก่อนอาร์กิวเมนต์แรก
SPLIT_BEFORE_LOGICAL_OPERATOR
ตั้งค่าเป็น
True
เพื่อต้องการแยกก่อนand
หรือor
หลัง
SPLIT_BEFORE_NAMED_ASSIGNS
แบ่งการมอบหมายที่มีชื่อออกเป็นแต่ละบรรทัด
SPLIT_COMPLEX_COMPREHENSION
สำหรับรายการความเข้าใจและนิพจน์ตัวสร้างที่มีหลายส่วนคำสั่ง (เช่น หลายส่วน
for
การเรียกif
นิพจน์ตัวกรอง) และจำเป็นต้องจัดเรียงใหม่ ให้แยกแต่ละส่วนย่อยออกเป็นบรรทัดของตัวเอง ตัวอย่างเช่น:
result = [
a_var + b_var for a_var in xrange ( 1000 ) for b_var in xrange ( 1000 )
if a_var % b_var ]
จะฟอร์แมตใหม่เป็นดังนี้:
result = [
a_var + b_var
for a_var in xrange ( 1000 )
for b_var in xrange ( 1000 )
if a_var % b_var ]
SPLIT_PENALTY_AFTER_OPENING_BRACKET
บทลงโทษสำหรับการแยกทันทีหลังวงเล็บเปิด
SPLIT_PENALTY_AFTER_UNARY_OPERATOR
บทลงโทษสำหรับการแยกบรรทัดหลังตัวดำเนินการเอกภาค
SPLIT_PENALTY_ARITHMETIC_OPERATOR
โทษของการแยกบรรทัดรอบตัวดำเนินการ
+
,-
,*
,/
,//
,%
และ@
SPLIT_PENALTY_BEFORE_IF_EXPR
บทลงโทษสำหรับการแยกทางขวาก่อนนิพจน์
if
SPLIT_PENALTY_BITWISE_OPERATOR
โทษของการแยกบรรทัดรอบ
&
,|
และตัวดำเนินการ^
SPLIT_PENALTY_COMPREHENSION
บทลงโทษสำหรับการแยกรายการความเข้าใจหรือนิพจน์ตัวสร้าง
SPLIT_PENALTY_EXCESS_CHARACTER
บทลงโทษสำหรับอักขระที่เกินขีดจำกัดของคอลัมน์
SPLIT_PENALTY_FOR_ADDED_LINE_SPLIT
การลงโทษเกิดขึ้นโดยการเพิ่มเส้นแบ่งให้กับเส้นตรรกะ ยิ่งมีการแบ่งบรรทัดมากเท่าใด บทลงโทษก็จะยิ่งสูงขึ้นเท่านั้น
SPLIT_PENALTY_IMPORT_NAMES
โทษของการแยกรายการ
import as
ชื่อ ตัวอย่างเช่น:
from a_very_long_or_indented_module_name_yada_yad import ( long_argument_1 ,
long_argument_2 ,
long_argument_3 )
จะฟอร์แมตใหม่เป็นดังนี้:
from a_very_long_or_indented_module_name_yada_yad import (
long_argument_1 , long_argument_2 , long_argument_3 )
SPLIT_PENALTY_LOGICAL_OPERATOR
โทษของการแยกเส้นรอบตัวดำเนินการ
and
และor
USE_TABS
ใช้อักขระ Tab สำหรับการเยื้อง
YAPF พยายามอย่างหนักเพื่อให้การจัดรูปแบบถูกต้อง แต่สำหรับโค้ดบางตัว มันจะไม่ดีเท่ากับการจัดรูปแบบด้วยมือ โดยเฉพาะอย่างยิ่ง ตัวอักษรข้อมูลขนาดใหญ่อาจเสียโฉมอย่างน่าสยดสยองภายใต้ YAPF
เหตุผลนี้มีหลายประการ กล่าวโดยสรุป YAPF เป็นเพียงเครื่องมือที่ช่วยในการพัฒนา มันจะจัดรูปแบบสิ่งต่าง ๆ ให้ตรงกับคำแนะนำสไตล์ แต่อาจไม่เท่ากับความสามารถในการอ่าน
สิ่งที่สามารถทำได้เพื่อบรรเทาสถานการณ์นี้คือการระบุว่าภูมิภาคที่ YAPF ควรละเว้นเมื่อทำการฟอร์แมตบางสิ่งใหม่:
# yapf: disable
FOO = {
# ... some very large, complex data literal.
}
BAR = [
# ... another large data literal.
]
# yapf: enable
คุณยังสามารถปิดใช้งานการจัดรูปแบบสำหรับตัวอักษรตัวเดียวได้ดังนี้:
BAZ = {
( 1 , 2 , 3 , 4 ),
( 5 , 6 , 7 , 8 ),
( 9 , 10 , 11 , 12 ),
} # yapf: disable
เพื่อรักษาวงเล็บปิดแบบแยกไว้อย่างสวยงาม ให้ใช้ dedent_closing_brackets
ในสไตล์ของคุณ โปรดทราบว่าในกรณีนี้ วงเล็บทั้งหมด รวมถึงคำจำกัดความของฟังก์ชันและการเรียกใช้ จะใช้สไตล์นั้น สิ่งนี้ให้ความสอดคล้องกันในโค้ดเบสที่จัดรูปแบบแล้ว
เราต้องการใช้อัลกอริธึมการจัดรูปแบบใหม่ของ clang-format มันทรงพลังมากและได้รับการออกแบบมาให้มีการจัดรูปแบบที่ดีที่สุดเท่าที่จะเป็นไปได้ เครื่องมือที่มีอยู่ถูกสร้างขึ้นโดยคำนึงถึงเป้าหมายที่แตกต่างกัน และจะต้องมีการแก้ไขอย่างกว้างขวางเพื่อแปลงไปใช้อัลกอริทึมของรูปแบบเสียงดังกราว
กรุณาทำ! YAPF ได้รับการออกแบบมาเพื่อใช้เป็นไลบรารีและเครื่องมือบรรทัดคำสั่ง ซึ่งหมายความว่าเครื่องมือหรือปลั๊กอิน IDE สามารถใช้ YAPF ได้ฟรี
YAPF พยายามอย่างหนักเพื่อให้เป็นไปตามมาตรฐาน PEP 8 โดยสมบูรณ์ อย่างไรก็ตาม สิ่งสำคัญอย่างยิ่งที่จะไม่เสี่ยงต่อการเปลี่ยนแปลงความหมายของโค้ดของคุณ ดังนั้น YAPF พยายามที่จะปลอดภัยที่สุดเท่าที่จะเป็นไปได้ และไม่เปลี่ยนสตรีมโทเค็น (เช่น โดยการเพิ่มวงเล็บ) อย่างไรก็ตาม กรณีทั้งหมดเหล่านี้สามารถแก้ไขได้ด้วยตนเองอย่างง่ายดาย ตัวอย่างเช่น
from my_package import my_function_1 , my_function_2 , my_function_3 , my_function_4 , my_function_5
FOO = my_variable_1 + my_variable_2 + my_variable_3 + my_variable_4 + my_variable_5 + my_variable_6 + my_variable_7 + my_variable_8
จะไม่ถูกแยก แต่คุณสามารถทำให้ถูกต้องได้อย่างง่ายดายเพียงเพิ่มวงเล็บ:
from my_package import ( my_function_1 , my_function_2 , my_function_3 ,
my_function_4 , my_function_5 )
FOO = ( my_variable_1 + my_variable_2 + my_variable_3 + my_variable_4 +
my_variable_5 + my_variable_6 + my_variable_7 + my_variable_8 )
โครงสร้างข้อมูลหลักใน YAPF คืออ็อบเจ็กต์ LogicalLine
มันเก็บรายการ FormatToken
s ที่เราต้องการวางไว้ในบรรทัดเดียวหากไม่มีขีดจำกัดคอลัมน์ ข้อยกเว้นในการแสดงความคิดเห็นที่อยู่ตรงกลางของคำสั่งนิพจน์จะบังคับให้บรรทัดนั้นถูกจัดรูปแบบมากกว่าหนึ่งบรรทัด ตัวจัดรูปแบบทำงานบนวัตถุ LogicalLine
ครั้งละหนึ่งวัตถุ
โดยทั่วไป LogicalLine
จะไม่ส่งผลต่อการจัดรูปแบบของบรรทัดก่อนหรือหลังบรรทัด มีส่วนหนึ่งของอัลกอริธึมที่อาจรวม LogicalLine
s ตั้งแต่สองตัวขึ้นไปไว้ในบรรทัดเดียว ตัวอย่างเช่น คำสั่ง if-then ที่มีเนื้อหาสั้นสามารถวางในบรรทัดเดียวได้:
if a == 42 : continue
อัลกอริธึมการจัดรูปแบบของ YAPF จะสร้างแผนผังถ่วงน้ำหนักซึ่งทำหน้าที่เป็นพื้นที่โซลูชันสำหรับอัลกอริธึม แต่ละโหนดในแผนผังแสดงถึงผลลัพธ์ของการตัดสินใจจัดรูปแบบ --- กล่าวคือ ว่าจะแยกหรือไม่แยกก่อนโทเค็น การตัดสินใจจัดรูปแบบแต่ละครั้งมีค่าใช้จ่ายที่เกี่ยวข้อง ดังนั้นต้นทุนจึงเกิดขึ้นที่ขอบระหว่างสองโหนด (ในความเป็นจริง แผนภูมิถ่วงน้ำหนักไม่มีวัตถุขอบแยกกัน ดังนั้นต้นทุนจึงอยู่ที่โหนดเอง)
ตัวอย่างเช่น ใช้ข้อมูลโค้ด Python ต่อไปนี้ เพื่อประโยชน์ของตัวอย่างนี้ สมมติว่าบรรทัด (1) ฝ่าฝืนข้อจำกัดขีดจำกัดของคอลัมน์และจำเป็นต้องจัดรูปแบบใหม่
def xxxxxxxxxxx ( aaaaaaaaaaaa , bbbbbbbbb , cccccccc , dddddddd , eeeeee ): # 1
pass # 2
สำหรับบรรทัด (1) อัลกอริธึมจะสร้างแผนผังโดยที่แต่ละโหนด (ออบเจ็กต์ FormattingDecisionState
) คือสถานะของบรรทัดที่โทเค็นนั้น โดยพิจารณาว่าจะแยกก่อนโทเค็นหรือไม่ หมายเหตุ: ออบเจ็กต์ FormatDecisionState
จะถูกคัดลอกตามค่า ดังนั้นแต่ละโหนดในกราฟจะไม่ซ้ำกัน และการเปลี่ยนแปลงในโหนดหนึ่งจะไม่ส่งผลกระทบต่อโหนดอื่นๆ
การวิเคราะห์พฤติกรรมใช้เพื่อกำหนดต้นทุนของการแยกหรือไม่แยก เนื่องจากโหนดรักษาสถานะของแผนผังจนถึงการแทรกของโทเค็น จึงสามารถระบุได้อย่างง่ายดายว่าการตัดสินใจแยกจะละเมิดข้อกำหนดด้านรูปแบบข้อใดข้อหนึ่งหรือไม่ ตัวอย่างเช่น ฮิวริสติกสามารถใช้การลงโทษเพิ่มเติมกับ Edge เมื่อไม่แยกระหว่างโทเค็นก่อนหน้าและโทเค็นที่ถูกเพิ่ม
มีบางกรณีที่เราไม่สามารถแยกบรรทัดได้ เนื่องจากการทำเช่นนี้จะส่งผลเสียเสมอ (เช่น จะต้องขึ้นบรรทัดใหม่ด้วยเครื่องหมายแบ็กสแลช ซึ่งไม่ค่อยพึงปรารถนานัก) สำหรับบรรทัด (1) เราจะไม่ต้องการแยกโทเค็นสามตัวแรก: def
, xxxxxxxxxxx
และ (
และเราจะไม่ต้องการที่จะแยกระหว่าง )
และ :
ในตอนท้าย ภูมิภาคเหล่านี้กล่าวกันว่า "ไม่แตกหัก" สิ่งนี้สะท้อนให้เห็นในแผนภูมิโดยไม่มีการตัดสินใจแบบ "แยก" (สาขาซ้ายมือ) ภายในภูมิภาคที่ไม่สามารถแตกหักได้
ตอนนี้เรามีแผนผังแล้ว เราจะพิจารณาว่าการจัดรูปแบบที่ "ดีที่สุด" คืออะไรโดยการค้นหาเส้นทางผ่านแผนผังที่มีต้นทุนต่ำที่สุด
แค่นั้นแหละ!