使用Python结束大括号

13

PEP 8 的代码示例存在冲突(在我看来),我想知道在放置闭括号时的惯例是什么。
缩进部分,闭括号与参数放在同一行。而在底部附近,它讨论了放置方式,并且指出:

多行结构中的闭括号/方括号/圆括号可以与最后一行列表的第一个非空白字符对齐[...],也可以与开始多行结构的行的第一个字符对齐[...]

这直接与上面的代码示例相矛盾。
对于多行语句,您通常在哪里放置闭括号,并且您认为遵循哪种惯例是最佳实践?

为了清楚起见,这里是演示不同之处的代码示例。

foo = long_function_name(
    var_one, var_two,
    var_three, var_four)

result = some_function_that_takes_arguments(
    'a', 'b', 'c',
    'd', 'e', 'f',
    )

result = some_function_that_takes_arguments(
    'a', 'b', 'c',
    'd', 'e', 'f',
)

1
最好引用你所参考的例子以及为什么认为这是矛盾的:你对读者施加的努力越少,就越有可能得到答案。 - Julien
1
这可能听起来像是推卸责任,但说实话,最容易阅读的方式就是最好的方式。通常我会将其放在与最后一个参数相同的行上,但如果该参数是函数调用并且有自己的括号,或者嵌套层次很深,我通常会将其放在下一行。 - Turksarama
就记录而言,询问一个(表面上的?)矛盾是合理的,但询问个人偏好则是不相关的话题。 - Julien
@Julien 我的错误,我尝试让它保持简洁。过去我的大部分帖子都被移除了代码示例。然而我认为这并不是离题,我正在询问有经验的Python开发人员如何放置括号,因为这就构成了约定。 - Jacob Stein
符不符合PEP规范是客观的,因此这是一个有效的问题,但接受的PEP选项中的个人偏好(意味着有经验的开发人员会使用两种方法)纯属基于个人意见,因此属于离题。 - Julien
3个回答

7
你提到的两个部分是不同的,第一个部分讲的是跟随块(如多行defif语句)的连续行,而第二个部分则是关于赋值和函数调用时的闭合括号和括号。当开始一个块时,你不希望将闭合括号放在下一行的开头,因为回到原始缩进表示块的结束。以下是几个明显看起来奇怪的例子:
def long_function_foo(
    var_one, var_two, var_three,
    var_four
):
    print('This code really looks out of place')

def long_function_bar(
   var_one,
   var_two
):
    print('and so does this one')

PEP8 允许使用所谓的垂直对齐方式,各种 PEP 中的许多示例都使用了这种约定,这已成为 Python IDE 的自动化特性:

def long_function_name(var_one, var_two, var_three,
                       var_four, var_five):
    """Documentation would go here, which makes it look better."""
    print(var_one + var_two + var_three)

但我个人避免使用它。这是一个基于观点的话题,但我不喜欢依赖于特定数量空格的对齐方式。这很繁琐且过于依赖IDE智能缩进。我更喜欢这种表示法,它被PEP8允许,但似乎不太流行。请注意,双重缩进用于与函数体区分:

def long_function_name(
        alpha, bravo, charlie, delta, echo, foxtrot,
        hotel, indiana):
    """Documentation would go here."""
    print(var_one + var_two + var_three)

当涉及到函数调用和赋值时,PEP8没有明确的答案。有人可能会缩进右括号,以模仿当下一条指令缩进较少时块的结尾。

foo = bar(
    1, 2, 3
    )

竖直对齐非常流行,我承认它看起来很好,但是我不想强制未来读者在我的代码中使用缩进大小,所以我避免使用它:

foo = bar(1, 2, 3, 5, 6, 7, 8, 9,
          10, 11, 12, 13, 14)

或者也可以把右括号/右圆括号放在靠左的位置:

foo = bar(
    1, 2, 3
)

我来自C++、Java和JavaScript背景,我使用后者的选项。从技术上讲,你也可以将右括号放在与参数相同的行上,但这会使它看起来像是一个缩进的代码块,这不符合我的口味,而且我没有见过人们这样做。


1
我感谢你详细的回答,谢谢。我也遵循了后一种函数调用约定,因为它似乎与C#相似。 - Jacob Stein
那是非常清晰明了的答案,谢谢。您认为最后一个示例与参数放在同一行的闭括号怎么样?这不符合 PEP 8(也不符合您上一个示例),但我非常喜欢它并且它与后续块的连续行保持一致。 - Géry Ogam
顺便说一下:我还没有接受任何答案,我非常想知道您对如何打破这个Python行的看法在这里 - Géry Ogam
我认为当你只有一行参数时,看起来有点奇怪,但我没有任何理性的支持或反对意见。至于长赋值语句,我像其他人在那个问题中提到的那样使用临时变量 :) - Domino

5

这里没有冲突,因为 PEP8 明确指出:

The closing brace/bracket/parenthesis on multiline constructs may either line up under the first non-whitespace character of the last line of list, as in:

my_list = [
    1, 2, 3,
    4, 5, 6,
    ]
result = some_function_that_takes_arguments(
    'a', 'b', 'c',
    'd', 'e', 'f',
    )

or it may be lined up under the first character of the line that starts the multiline construct, as in:

my_list = [
    1, 2, 3,
    4, 5, 6,
]
result = some_function_that_takes_arguments(
    'a', 'b', 'c',
    'd', 'e', 'f',
)

所以这两种约定都是可以接受的。

个人而言,我更喜欢后一种约定,但这只是我的个人偏好。


2
在缩进部分的顶部,多个代码示例中参数的最后一行是闭合括号。 - Jacob Stein

3
这是两个代码片段,一个来自谷歌的TensorFlow,另一个来自Facebook的PyTorch。
TensorFlow:
if (not input_saved_model_dir and
      not saver_lib.checkpoint_exists(input_checkpoint)):
    print("Input checkpoint '" + input_checkpoint + "' doesn't exist!")

Pytorch

ALL_TENSORTYPES = [torch.float,
                   torch.double,
                   torch.half]

在这两种情况下,它们都使用了相同的行结束大括号策略。因此,在我看来,最好遵循这个策略。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接