需求说明

python函数调用时,输入参数的字符数未达到一行最大的字符数限制,不换行。如果第i个输入参数最末字符超过了一行最大字符限制,则另起一行,且另起的行,起始位置要与第一个参数左对齐。
并且函数调用结束后的")",最后一个输入参数所在行的代码+")",总字符<=一行最大字符限制,那么这个")"不要另起一行。
即这个函数调用处的代码风格与这个google cpp 代码风格保持一致。
https://zh-google-styleguide.readthedocs.io/en/latest/google-...

举个例子:假设一行最大字符限制=80,我希望函数调用处的代码,按照如下例子格式化。

# 函数调用处,代码格式化的例子
result = function_name(first_parameter, second_parameter, third_parameter,
                       fourth_parameter, fifth_parameter)

具体设置

本博客中,yapf版本:0.40.2

对于yapf格式的配置文件:.style.yapf

[style]
based_on_style = google
column_limit = 120
split_before_first_argument = False
split_before_named_assigns = False
split_arguments_when_comma_terminated = False
allow_split_before_default_or_named_assigns = True
allow_split_before_dict_value = True
dedent_closing_brackets = False

测试命令行代码:

yapf --style=.style.yapf your_python_file

yapf格式的配置文件,对应的.toml格式的配置文件

[tool.yapf]
based_on_style = "google"
column_limit = 120
split_before_first_argument = false
split_before_named_assigns = false
split_arguments_when_comma_terminated = false
allow_split_before_default_or_named_assigns = true
allow_split_before_dict_value = true
dedent_closing_brackets = false

测试命令行代码:

yapf --style=pyproject.toml  your_python_file

设置内容解释

备注:本小节(设置内容解释),大部分内容来自于ChatGPT,仅供参考,不保证正确性。

[style]
based_on_style = google
column_limit = 120
split_before_first_argument = False
split_before_named_assigns = False
split_arguments_when_comma_terminated = False
allow_split_before_default_or_named_assigns = True
allow_split_before_dict_value = True
dedent_closing_brackets = False

split_before_first_argument=False

# If an argument / parameter list is going to be split, then split before
# the first argument.
split_before_first_argument=False

这段配置说明的是:
split_before_first_argument = False
当函数或方法调用的参数列表需要进行换行时,不会在第一个参数之前进行换行,而是尽量将第一个参数与函数名保持在同一行。
例如:
split_before_first_argument = False 时,函数调用会被格式化为:

func_call(arg1, arg2, arg3, 
          named_arg1=value1, named_arg2=value2)

如果设置为 True,则会在第一个参数之前换行:

func_call(
    arg1, arg2, arg3, 
    named_arg1=value1, named_arg2=value2
)

split_before_named_assigns=False

# Split named assignments onto individual lines.
split_before_named_assigns=False

这段配置控制的是命名参数(即带有赋值的参数)的换行行为。

split_before_named_assigns = False 表示当遇到命名参数(比如 key=value 形式的参数)时,不会在这些参数的赋值符号(=)之前进行换行,只有在行超出列限制时才会进行换行,并尽量保持参数紧凑在一行内。

split_before_named_assigns = True 则会在命名参数前换行,使得每个命名参数占据单独一行。

例如:

split_before_named_assigns = False 的效果是:

func_call(arg1, arg2, named_arg1=value1, named_arg2=value2)

split_before_named_assigns = True 会格式化为:

func_call(
  arg1, arg2, 
  named_arg1=value1, 
  named_arg2=value2
)

split_before_named_assigns = False 的情况下,YAPF 尽量会将命名参数保持在同一行,除非行长度超过列限制(如 column_limit = 120)。

split_arguments_when_comma_terminated = False

# Split before arguments if the argument list is terminated by a
# comma.
split_arguments_when_comma_terminated=False

split_arguments_when_comma_terminated = False
该配置项控制当函数参数列表以逗号结尾时,YAPF是否应在参数列表中的每个参数前换行。

split_arguments_when_comma_terminated = False 表示即使参数列表以逗号结束,也不会强制在每个参数前换行。YAPF会尽量将参数放在同一行,直到列长度超过column_limit

split_arguments_when_comma_terminated = True 则会在参数列表以逗号结束时,在每个参数前换行,无论参数列表是否超出列限制。
例如,假设函数调用时参数列表以逗号结束:
split_arguments_when_comma_terminated = False 会保持参数尽量在同一行:

func_call(arg1, arg2, arg3,)

split_arguments_when_comma_terminated = True 则会在每个参数前换行:

func_call(
  arg1,
  arg2,
  arg3,
)

在你的配置中,split_arguments_when_comma_terminated = False意味着YAPF只会在必要时(如超出列限制时)才对参数列表进行换行,而不是因为逗号而强制换行。

allow_split_before_default_or_named_assigns = True

# Allow splitting before a default / named assignment in an argument list.
allow_split_before_default_or_named_assigns=True

allow_split_before_default_or_named_assigns = True
该配置项控制在函数参数列表中,YAPF是否允许在带有默认值或命名参数之前进行换行。

allow_split_before_default_or_named_assigns = True 表示在参数列表较长或超出列限制时,YAPF可以在带有默认值或命名的参数(如param=value)之前进行换行,使代码更加整齐和可读。

allow_split_before_default_or_named_assigns = False 则会尽量避免在带有默认值或命名的参数前换行。

示例:
如果开启此选项(True),YAPF可能会在默认值参数前换行:

def my_function(
    arg1,
    arg2,
    arg3=None,
    arg4=5,
):

如果设置为False,则YAPF会尽量将参数放在同一行,除非超出列限制:

def my_function(arg1, arg2, arg3=None, arg4=5):

在你的配置中,allow_split_before_default_or_named_assigns = True意味着YAPF会允许在必要时对带默认值或命名参数的地方换行,从而提升代码的可读性。

allow_split_before_dict_value = True

# Allow splits before the dictionary value.
allow_split_before_dict_value=True

allow_split_before_dict_value = True
该配置项控制在字典表达式中,是否允许在字典键和值之间进行换行。
allow_split_before_dict_value = True:当字典的键值对超出列限制时,允许在键和值之间换行,使代码在视觉上更整齐易读。
allow_split_before_dict_value = False:尽量避免在键和值之间换行,即使字典的键值对长度超出列限制,YAPF也会尝试将键和值放在同一行。

示例

如果 allow_split_before_dict_value = True
YAPF 可能会在键值对的值之前换行,如下所示:

my_dict = {
    'long_key_1': 'a very long value that requires wrapping to the next line',
    'key_2': 'value2'
}

如果 allow_split_before_dict_value = False
即使字典的值很长,YAPF也会尽量将键和值放在同一行,除非必须换行:

my_dict = {
    'long_key_1': 'a very long value that requires wrapping to the next line', 'key_2': 'value2'
}

在你的配置中,allow_split_before_dict_value = True 将会让YAPF在必要时对字典的值进行换行,使得长字典值在格式化时更整齐可读。

dedent_closing_brackets = False

# Do not split consecutive brackets. Only relevant when
# dedent_closing_brackets is set. For example:
#
#    call_func_that_takes_a_dict(
#        {
#            'key1': 'value1',
#            'key2': 'value2',
#        }
#    )
#
# would reformat to:
#
#    call_func_that_takes_a_dict({
#        'key1': 'value1',
#        'key2': 'value2',
#    })
coalesce_brackets=False

注释内容,没看懂,实测下来,如果设置为True,函数调用结尾的“)”如下:

    img = None
    top = 0
    bottom111111111111111111111111 = 0
    left = 0
    right = 0
    pad_color = (0, 0, 0)
    res = cv2.copyMakeBorder(
        img, top, bottom111111111111111111111111, left, right, cv2.BORDER_CONSTANT, value=pad_color
    )

如果设置为False,函数调用结尾的“)”如下:

    img = None
    top = 0
    bottom1111111111111111111111111111111111111111111111111111111111111111111111 = 0
    bottom111111111111111111111111 = 0
    left = 0
    right = 0
    pad_color = (0, 0, 0)
    res = cv2.copyMakeBorder(img, top, bottom111111111111111111111111, left, right, cv2.BORDER_CONSTANT,
                             value=pad_color)

yapf style可以设置的内容查询

打印yapf可以设置的键值对与含义的命令。

yapf --style-help

具体内容如下:

[style]
# Align closing bracket with visual indentation.
align_closing_bracket_with_visual_indent=False

# Allow dictionary keys to exist on multiple lines. For example:
#
#   x = {
#       ('this is the first element of a tuple',
#        'this is the second element of a tuple'):
#            value,
#   }
allow_multiline_dictionary_keys=False

# Allow lambdas to be formatted on more than one line.
allow_multiline_lambdas=False

# Allow splitting before a default / named assignment in an argument list.
allow_split_before_default_or_named_assigns=True

# Allow splits before the dictionary value.
allow_split_before_dict_value=True

#   Let spacing indicate operator precedence. For example:
#
#     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
#
# will be formatted as follows to indicate precedence:
#
#     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
#
arithmetic_precedence_indication=False

# Number of blank lines surrounding top-level function and class
# definitions.
blank_lines_around_top_level_definition=2

# Number of blank lines between top-level imports and variable
# definitions.
blank_lines_between_top_level_imports_and_variables=1

# Insert a blank line before a class-level docstring.
blank_line_before_class_docstring=False

# Insert a blank line before a module docstring.
blank_line_before_module_docstring=False

# Insert a blank line before a 'def' or 'class' immediately nested
# within another 'def' or 'class'. For example:
#
#   class Foo:
#                      # <------ this blank line
#     def method():
#       pass
blank_line_before_nested_class_or_def=True

# Do not split consecutive brackets. Only relevant when
# dedent_closing_brackets is set. For example:
#
#    call_func_that_takes_a_dict(
#        {
#            'key1': 'value1',
#            'key2': 'value2',
#        }
#    )
#
# would reformat to:
#
#    call_func_that_takes_a_dict({
#        'key1': 'value1',
#        'key2': 'value2',
#    })
coalesce_brackets=False

# The column limit.
column_limit=120

# The style for continuation alignment. Possible values are:
#
# - SPACE: Use spaces for continuation alignment. This is default behavior.
# - FIXED: Use fixed number (CONTINUATION_INDENT_WIDTH) of columns
#   (ie: CONTINUATION_INDENT_WIDTH/INDENT_WIDTH tabs or
#   CONTINUATION_INDENT_WIDTH spaces) for continuation alignment.
# - VALIGN-RIGHT: Vertically align continuation lines to multiple of
#   INDENT_WIDTH columns. Slightly right (one tab or a few spaces) if
#   cannot vertically align continuation lines with indent characters.
continuation_align_style=SPACE

# Indent width used for line continuations.
continuation_indent_width=4

# Put closing brackets on a separate line, dedented, if the bracketed
# expression can't fit in a single line. Applies to all kinds of brackets,
# including function definitions and calls. For example:
#
#   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
dedent_closing_brackets=False

# Disable the heuristic which places each list element on a separate line
# if the list is comma-terminated.
disable_ending_comma_heuristic=False

# Place each dictionary entry onto its own line.
each_dict_entry_on_separate_line=True

# Require multiline dictionary even if it would normally fit on one line.
# For example:
#
#   config = {
#       'key1': 'value1'
#   }
force_multiline_dict=False

# The regex for an i18n comment. The presence of this comment stops
# reformatting of that line, because the comments are required to be
# next to the string they translate.
i18n_comment=#\..*

# The i18n function call names. The presence of this function stops
# reformattting on that line, because the string it has cannot be moved
# away from the i18n comment.
i18n_function_call=N_, _

# Indent blank lines.
indent_blank_lines=False

# Put closing brackets on a separate line, indented, if the bracketed
# expression can't fit in a single line. Applies to all kinds of brackets,
# including function definitions and calls. For example:
#
#   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_closing_brackets=False

# Indent the dictionary value if it cannot fit on the same line as the
# dictionary key. For example:
#
#   config = {
#       'key1':
#           'value1',
#       'key2': value1 +
#               value2,
#   }
indent_dictionary_value=True

# The number of columns to use for indentation.
indent_width=4

# Join short lines into one line. E.g., single line 'if' statements.
join_multiple_lines=False

# Do not include spaces around selected binary operators. For example:
#
#   1 + 2 * 3 - 4 / 5
#
# will be formatted as follows when configured with "*,/":
#
#   1 + 2*3 - 4/5
no_spaces_around_selected_binary_operators=

# Use spaces around default or named assigns.
spaces_around_default_or_named_assign=False

# Adds a space after the opening '{' and before the ending '}' dict
# delimiters.
#
#   {1: 2}
#
# will be formatted as:
#
#   { 1: 2 }
spaces_around_dict_delimiters=False

# Adds a space after the opening '[' and before the ending ']' list
# delimiters.
#
#   [1, 2]
#
# will be formatted as:
#
#   [ 1, 2 ]
spaces_around_list_delimiters=False

# Use spaces around the power operator.
spaces_around_power_operator=False

# Use spaces around the subscript / slice operator.  For example:
#
#   my_list[1 : 10 : 2]
spaces_around_subscript_colon=False

# Adds a space after the opening '(' and before the ending ')' tuple
# delimiters.
#
#   (1, 2, 3)
#
# will be formatted as:
#
#   ( 1, 2, 3 )
spaces_around_tuple_delimiters=False

# The number of spaces required before a trailing comment.
# This can be a single value (representing the number of spaces
# before each trailing comment) or list of values (representing
# alignment column values; trailing comments within a block will
# be aligned to the first column value that is greater than the maximum
# line length within the block). For example:
#
# With spaces_before_comment=5:
#
#   1 + 1 # Adding values
#
# will be formatted as:
#
#   1 + 1     # Adding values <-- 5 spaces between the end of the
#             # statement and comment
#
# With 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
#
# will be formatted as:
#
#   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
#
spaces_before_comment=2

# Insert a space between the ending comma and closing bracket of a list,
# etc.
space_between_ending_comma_and_closing_bracket=False

# 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 }
space_inside_brackets=False

# Split before arguments.
split_all_comma_separated_values=False

# Split before arguments, but do not split all subexpressions recursively
# (unless needed).
split_all_top_level_comma_separated_values=False

# Split before arguments if the argument list is terminated by a
# comma.
split_arguments_when_comma_terminated=False

# Set to True to prefer splitting before '+', '-', '*', '/', '//', or '@'
# rather than after.
split_before_arithmetic_operator=False

# Set to True to prefer splitting before '&', '|' or '^' rather than
# after.
split_before_bitwise_operator=False

# Split before the closing bracket if a list or dict literal doesn't fit on
# a single line.
split_before_closing_bracket=True

# Split before a dictionary or set generator (comp_for). For example, note
# the split before the 'for':
#
#   foo = {
#       variable: 'Hello world, have a nice day!'
#       for variable in bar if variable != 42
#   }
split_before_dict_set_generator=False

# Split before the '.' if we need to split a longer expression:
#
#   foo = ('This is a really long string: {}, {}, {}, {}'.format(a, b, c, d))
#
# would reformat to something like:
#
#   foo = ('This is a really long string: {}, {}, {}, {}'
#          .format(a, b, c, d))
split_before_dot=False

# Split after the opening paren which surrounds an expression if it doesn't
# fit on a single line.
split_before_expression_after_opening_paren=False

# If an argument / parameter list is going to be split, then split before
# the first argument.
split_before_first_argument=False

# Set to True to prefer splitting before 'and' or 'or' rather than
# after.
split_before_logical_operator=False

# Split named assignments onto individual lines.
split_before_named_assigns=False

# Set to True to split list comprehensions and generators that have
# non-trivial expressions and multiple clauses before each of these
# clauses. For example:
#
#   result = [
#       a_long_var + 100 for a_long_var in xrange(1000)
#       if a_long_var % 10]
#
# would reformat to something like:
#
#   result = [
#       a_long_var + 100
#       for a_long_var in xrange(1000)
#       if a_long_var % 10]
split_complex_comprehension=True

# The penalty for splitting right after the opening bracket.
split_penalty_after_opening_bracket=300

# The penalty for splitting the line after a unary operator.
split_penalty_after_unary_operator=10000

# The penalty of splitting the line around the '+', '-', '*', '/', '//',
# `%`, and '@' operators.
split_penalty_arithmetic_operator=300

# The penalty for splitting right before an if expression.
split_penalty_before_if_expr=0

# The penalty of splitting the line around the '&', '|', and '^' operators.
split_penalty_bitwise_operator=300

# The penalty for splitting a list comprehension or generator
# expression.
split_penalty_comprehension=2100

# The penalty for characters over the column limit.
split_penalty_excess_character=7000

# The penalty incurred by adding a line split to the logical line. The
# more line splits added the higher the penalty.
split_penalty_for_added_line_split=30

# The penalty of splitting a list of "import as" names. For example:
#
#   from a_very_long_or_indented_module_name_yada_yad import (long_argument_1,
#                                                             long_argument_2,
#                                                             long_argument_3)
#
# would reformat to something like:
#
#   from a_very_long_or_indented_module_name_yada_yad import (
#       long_argument_1, long_argument_2, long_argument_3)
split_penalty_import_names=0

# The penalty of splitting the line around the 'and' and 'or' operators.
split_penalty_logical_operator=300

# Use the Tab character for indentation.
use_tabs=False



楚知行
18 声望4 粉丝