YAPF — это форматтер Python, основанный на clang-format
(разработанный Дэниелом Джаспером). По сути, алгоритм берет код и вычисляет наилучшее форматирование, соответствующее настроенному стилю. Это снимает с вас большую часть рутинной работы по поддержанию вашего кода.
Конечная цель состоит в том, чтобы код, создаваемый 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
и изменит его, чтобы он имел два пробельных отступа.
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
: либо имя стиля, либо путь к файлу, содержащему настройки стиля форматирования. Если указано значение None, используйте стиль по умолчанию, заданный в style.DEFAULT_STYLE_FACTORY
.
> >> FormatCode ( "def g(): n return True" , style_config = 'pep8' )[ 0 ]
'def g(): n return True n '
Аргумент lines
: список кортежей строк (целые числа), [начало, конец], которые мы хотим отформатировать. Строки индексируются с отсчетом от 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
— это то, что вставляется в файл 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
Вставьте пустую строку перед строкой документации уровня класса.
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
, который управляет разделением, когда список содержит комментарий. Чтобы получить старое поведение, установите для обоих флагов значение true. Подробная информация на сайте CHANGELOG.md.
DISABLE_SPLIT_LIST_WITH_COMMENT
Не помещайте каждый элемент на новую строку в списке, содержащем промежуточные комментарии.
Без этого флага (по умолчанию):
[ a, b, # c ]
С этим флагом:
[ a, b, # c ]
Это отражает поведение формата clang и полезно для формирования «логических групп» элементов в списке. Это также работает в объявлениях функций.
EACH_DICT_ENTRY_ON_SEPARATE_LINE
Поместите каждую словарную статью на отдельную строку.
FORCE_MULTILINE_DICT
Соблюдайте
EACH_DICT_ENTRY_ON_SEPARATE_LINE
даже если строка корочеCOLUMN_LIMIT
.
I18N_COMMENT
Регулярное выражение для комментария интернационализации. Наличие этого комментария останавливает переформатирование этой строки, поскольку комментарии должны находиться рядом со строкой, которую они переводят.
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
Добавляет пробел после открывающего '{' и перед конечными разделителями '}'.
{ 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
Используйте символ табуляции для отступа.
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 потребуются обширные модификации.
Пожалуйста, сделайте! 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
строк в одну строку. Например, оператор if-then с коротким телом можно разместить в одной строке:
if a == 42 : continue
Алгоритм форматирования YAPF создает взвешенное дерево, которое выступает в качестве пространства решений для алгоритма. Каждый узел в дереве представляет собой результат решения о форматировании, т. е. разбивать или не разбивать перед токеном. Каждое решение по форматированию имеет свою стоимость. Таким образом, стоимость реализуется на границе между двумя узлами. (На самом деле взвешенное дерево не имеет отдельных реберных объектов, поэтому стоимость приходится на сами узлы.)
Например, возьмите следующий фрагмент кода Python. В этом примере предположим, что строка (1) нарушает ограничение на ограничение столбца и ее необходимо переформатировать.
def xxxxxxxxxxx ( aaaaaaaaaaaa , bbbbbbbbb , cccccccc , dddddddd , eeeeee ): # 1
pass # 2
Для строки (1) алгоритм построит дерево, в котором каждый узел (объект FormattingDecisionState
) представляет собой состояние строки в этом токене с учетом решения о разделении до токена или нет. Примечание. Объекты FormatDecisionState
копируются по значению, поэтому каждый узел графа уникален, и изменение одного из них не влияет на другие узлы.
Эвристика используется для определения стоимости разделения или отказа от разделения. Поскольку узел хранит состояние дерева до вставки токена, он может легко определить, не нарушит ли решение о разделении одно из требований стиля. Например, эвристика может применять дополнительный штраф к ребру, если он не разделяется между предыдущим токеном и добавляемым.
В некоторых случаях мы никогда не захотим разбивать строку, потому что это всегда будет вредно (т. е. потребуется обратная косая черта-новая строка, что очень редко желательно). В строке (1) мы никогда не будем разделять первые три токена: def
, xxxxxxxxxxx
и (
. Мы также не хотим разделять между )
и :
в конце. Эти регионы называются «нерушимыми». В дереве это отражено тем, что в неразрывной области нет «разделенного» решения (левая ветвь).
Теперь, когда у нас есть дерево, мы определяем «лучшее» форматирование, находя путь через дерево с наименьшими затратами.
И все!