YAPF はclang-format
(Daniel Jasper によって開発) に基づく Python フォーマッタです。基本的に、アルゴリズムはコードを取得し、構成されたスタイルに準拠する最適な書式設定を計算します。コードを保守するための面倒な作業の多くが軽減されます。
最終的な目標は、YAPF が生成するコードが、プログラマーがスタイル ガイドに従っている場合に作成するコードと同じくらい優れたものになることです。
注: YAPF は Google の公式製品 (実験的かどうかにかかわらず) ではなく、Google がたまたま所有しているコードにすぎません。
PyPI から YAPF をインストールするには:
$ 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 はプログラムが正常に終了すると 0 を返し、それ以外の場合は 0 以外を返します。
--diff
が指定されている場合、YAPF は変更が必要な場合は 0 を返し、それ以外の場合は 0 以外を返します (プログラム エラーを含む)。これを CI ワークフローで使用して、コードが YAPF 形式であることをテストできます。
YAPF は、コマンドラインで指定されたパターンを除外するだけでなく、YAPF の呼び出し元の作業ディレクトリにある.yapfignore
またはpyproject.toml
という名前のファイルで指定された追加のパターンを検索します。
.yapfignore
の構文は、UNIX のファイル名パターン マッチングに似ています。
* matches everything
? matches any single character
[seq] matches any character in seq
[!seq] matches any character not in seq
エントリを./
で始めてはいけないことに注意してください。
pyproject.toml
を使用する場合、除外パターンは[tool.yapfignore]
セクションのignore_patterns
キーで指定します。例えば:
[tool.yapfignore]
ignore_patterns = [
" temp/**/*.py " ,
" temp2/*.py "
]
YAPF で使用される書式設定スタイルは構成可能であり、YAPF が書式設定を行う方法を調整するために使用できる多くの「ノブ」があります。完全なリストについては、 style.py
モジュールを参照してください。
スタイルを制御するには、 --style
引数を指定して YAPF を実行します。事前定義されたスタイル ( pep8
やgoogle
など) の 1 つ、目的のスタイルを指定する構成ファイルへのパス、またはキーと値のペアの辞書を受け入れます。
設定ファイルは、 [style]
という見出しを持つ (大文字と小文字を区別しない) key = value
ペアの単純なリストです。例えば:
[style]
based_on_style = pep8
spaces_before_comment = 4
split_before_logical_operator = true
based_on_style
設定は、このカスタム スタイルがどの定義済みスタイルに基づいているかを決定します (サブクラス化のようなものだと考えてください)。 4 つのスタイルが事前定義されています。
pep8
(デフォルト)google
(Google Python スタイル ガイドに基づく)yapf
(Google オープンソース プロジェクトで使用)facebook
詳細については、 style.py
の_STYLE_NAME_TO_FACTORY
を参照してください。
辞書を使用してコマンドラインで同じことを行うこともできます。例えば:
--style= ' {based_on_style: pep8, indent_width: 2} '
これはpep8
基本スタイルを取得し、2 つのスペース インデントを持つように変更します。
YAPF は次の方法で書式設定スタイルを検索します。
.style.yapf
ファイルの[style]
セクション内。setup.cfg
ファイルの[yapf]
セクション。pyproject.toml
ファイルの[tool.yapf]
セクション内。~/.config/yapf/style
ファイルの[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 ]
YAPF を呼び出すための 2 つの主要な API は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
引数: スタイル名、または書式設定スタイル設定を含むファイルへのパス。 None が指定されている場合は、 style.DEFAULT_STYLE_FACTORY
で設定されているデフォルトのスタイルを使用します。
> >> FormatCode ( "def g(): n return True" , style_config = 'pep8' )[ 0 ]
'def g(): n return True n '
lines
引数: フォーマットする行のタプル (int)、[開始、終了] のリスト。行には 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): 再フォーマットされたソースを返す代わりに、フォーマットされたソースを再フォーマットされたソースに変換する diff を返します。
>>> print(FormatCode("a==b", filename="foo.py", print_diff=True)[0])
--- foo.py (original)
+++ foo.py (reformatted)
@@ -1 +1 @@
- a==b
+ a == b
注: FormatCode
のfilename
引数は diff に挿入されるもので、デフォルトは<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
ラムダを複数行でフォーマットできるようにします。
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
クラスレベルの docstring の前に空行を挿入します。
BLANK_LINE_BEFORE_MODULE_DOCSTRING
モジュールの 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
列の倍数に垂直に揃えます。インデント文字で継続行を垂直方向に揃えることができない場合は、わずかに右 (1 つのタブまたはいくつかのスペース)。
CONTINUATION_INDENT_WIDTH
行の継続に使用されるインデントの幅。
DEDENT_CLOSING_BRACKETS
括弧で囲まれた式が 1 行に収まらない場合は、閉じ括弧を別の行にデデントして配置します。関数定義や呼び出しを含む、あらゆる種類のかっこに適用されます。例えば:
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
リストがカンマで終了している場合、各リスト要素を別の行に配置するヒューリスティックを無効にします。
注: このフラグの動作は v0.40.3 で変更されました。以前は、このフラグが true の場合、末尾のカンマまたはコメントを含むリストを分割していました。現在、リストにコメントが含まれている場合の分割を制御する別のフラグ
DISABLE_SPLIT_LIST_WITH_COMMENT
が用意されています。以前の動作を取得するには、両方のフラグを true に設定します。詳細については、CHANGELOG.md を参照してください。
DISABLE_SPLIT_LIST_WITH_COMMENT
途中コメントを含むリスト内のすべての要素を新しい行に配置しないでください。
このフラグを使用しない場合 (デフォルト):
[ a, b, # c ]
このフラグを使用すると:
[ a, b, # c ]
これは、clang-format の動作を反映しており、リスト内の要素の「論理グループ」を形成するのに役立ちます。関数宣言でも機能します。
EACH_DICT_ENTRY_ON_SEPARATE_LINE
各辞書エントリをそれぞれの行に配置します。
FORCE_MULTILINE_DICT
行が
COLUMN_LIMIT
より短い場合でも、EACH_DICT_ENTRY_ON_SEPARATE_LINE
を尊重します。
I18N_COMMENT
国際化コメントの正規表現。コメントは翻訳される文字列の隣にある必要があるため、このコメントが存在するとその行の再フォーマットが停止します。
I18N_FUNCTION_CALL
国際化関数の呼び出し名。この関数が存在すると、この関数が持つ文字列を i18n コメントから遠ざけることができないため、その行での再フォーマットが停止します。
INDENT_BLANK_LINES
True
に設定すると、空行ではなくインデントされた空行が優先されます。
INDENT_CLOSING_BRACKETS
括弧で囲まれた式が 1 行に収まらない場合は、閉じ括弧をインデントして別の行に置きます。関数定義や呼び出しを含む、あらゆる種類のかっこに適用されます。例えば:
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
短い行を 1 行に結合します。たとえば、単一行の
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
開始 '{' の後と終了 '}' 辞書区切り文字の前にスペースを追加します。
{ 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
) の 1 行が長すぎる場合は、各要素が別の行になるように分割します。
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
リテラルが 1 行に収まらない場合は、右括弧の前で分割します。
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
式が 1 行に収まらない場合は、式を囲む開始括弧の後で分割します。
SPLIT_BEFORE_FIRST_ARGUMENT
引数/パラメータのリストを分割する場合は、最初の引数の前で分割します。
SPLIT_BEFORE_LOGICAL_OPERATOR
True
に設定すると、後ではなく前and
oror
分割されます。
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
インデントにはタブ文字を使用します。
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 の再フォーマット アルゴリズムを使用したいと考えていました。これは非常に強力で、可能な限り最高の書式設定を行うように設計されています。既存のツールはさまざまな目的を念頭に置いて作成されており、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
オブジェクトです。これには、列制限がない場合に 1 行に配置したいFormatToken
s のリストが保持されます。式ステートメントの途中にあるコメントを例外として、行を複数行にフォーマットする必要があります。フォーマッタは一度に 1 つのLogicalLine
オブジェクトに対して動作します。
通常、 LogicalLine
その前後の行の書式設定には影響しません。アルゴリズムの一部で、2 つ以上のLogicalLine
を 1 つの行に結合することがあります。たとえば、本文が短い if-then ステートメントは 1 行に配置できます。
if a == 42 : continue
YAPF の書式設定アルゴリズムは、アルゴリズムの解空間として機能する重み付きツリーを作成します。ツリー内の各ノードは、形式決定の結果、つまりトークンの前で分割するかどうかを表します。フォーマットの決定にはそれぞれコストがかかります。したがって、コストは 2 つのノード間のエッジで実現されます。 (実際には、重み付きツリーには個別のエッジ オブジェクトがないため、コストはノード自体に発生します。)
たとえば、次の Python コード スニペットを考えてみましょう。この例では、行 (1) が列制限の制限に違反しているため、再フォーマットする必要があると仮定します。
def xxxxxxxxxxx ( aaaaaaaaaaaa , bbbbbbbbb , cccccccc , dddddddd , eeeeee ): # 1
pass # 2
行 (1) の場合、アルゴリズムは、トークンの前で分割するかどうかを決定した場合の、各ノード ( FormattingDecisionState
オブジェクト) がそのトークンにおける行の状態であるツリーを構築します。注: FormatDecisionState
オブジェクトは値によってコピーされるため、グラフ内の各ノードは一意であり、1 つのノードを変更しても他のノードには影響しません。
ヒューリスティックは、分割するかどうかのコストを決定するために使用されます。ノードはトークンが挿入されるまでツリーの状態を保持するため、分割の決定がスタイル要件のいずれかに違反するかどうかを簡単に判断できます。たとえば、ヒューリスティックでは、前のトークンと追加されるトークンの間で分割しない場合に、エッジに追加のペナルティを適用できます。
場合によっては、行を分割したくない場合があります。分割すると常に悪影響が生じるからです (つまり、バックスラッシュと改行が必要になりますが、これが望ましいことはほとんどありません)。行 (1) では、最初の 3 つのトークン、 def
、 xxxxxxxxxxx
、 (
を分割したくありません。また、 )
と最後の:
の間でも分割したくありません。これらの領域は「破壊不可能」であると言われています。これは、解読不可能な領域内に「分割」決定 (左側の分岐) がないことによってツリーに反映されます。
ツリーを取得したので、コストが最も低いツリー内のパスを見つけて、「最適な」書式設定を決定します。
それで終わりです!