PEP 8 有冲突的代码示例(在我看来),我很好奇定位右大括号的约定是什么。
在缩进的顶部,它们与参数在同一行。在底部附近它讨论了定位,而是说:
多行结构上的右大括号/方括号/括号可以 要么在最后一个的第一个非空白字符下排队 list[...] 的行,或者它可以排列在列表的第一个字符下 开始多行构造的行[...]
这与上面的代码示例直接冲突。
您通常将多行语句的右大括号放在哪里,您认为就惯例而言最佳实践是什么?
为了清楚起见,以下是演示差异的代码示例。
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',
)
您提到的两个部分的不同之处在于,第一个部分是关于后面跟着一个块的连续行(例如多行
def
或 if
语句),而第二个部分是关于赋值和函数调用时的右大括号和括号。当开始一个块时,您不希望将右括号放在下一行的开头,因为返回到原始缩进会传达块的结尾。一些看起来显然很奇怪的例子:
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 背景,我使用后一种选择。从技术上讲,您也可以将右括号与参数放在同一行,但这使它看起来像一个缩进的代码块,太不符合我的口味,而且这不是我真正见过人们这样做的事情。
这里没有冲突,因为PEP8特别说:
多行结构上的右大括号/方括号/圆括号 可以 任一 在最后一个的第一个非空白字符下排列 列表行,如:
my_list = [ 1, 2, 3, 4, 5, 6, ] result = some_function_that_takes_arguments( 'a', 'b', 'c', 'd', 'e', 'f', )
或 它可能会排列在该行的第一个字符下方 启动多行构造,如下所示:
my_list = [ 1, 2, 3, 4, 5, 6, ] result = some_function_that_takes_arguments( 'a', 'b', 'c', 'd', 'e', 'f', )
所以这两种约定都是可以接受的。
我个人更喜欢后一种约定,但这只是我。
这是来自 google 的 Tensorflow 和 facebook 的 pytorch 的两个代码片段。
张量流
if (not input_saved_model_dir and
not saver_lib.checkpoint_exists(input_checkpoint)):
print("Input checkpoint '" + input_checkpoint + "' doesn't exist!")
火炬
ALL_TENSORTYPES = [torch.float,
torch.double,
torch.half]
在两者中,他们都使用了“同一行”右大括号策略。所以,在我看来,最好遵循这一点。
我们都同意,与其他编程语言不同,Python 使用缩进来指示代码块中语句的层次结构和分组,并通过缩进连续行来存档。
现在我不明白为什么多行结构上的右大括号/方括号/圆括号不属于这一类别,因为它们显然属于第一行的初始赋值。让我们看一个现实世界的例子来说明为什么这很重要:
import pandas as pd
# unpythonic and unfoldable:
def import_data_from_csv_v1(
file_path: str
) -> pd.DataFrame:
"""Read a CSV file and return a DataFrame."""
df = pd.read_csv(
file_path, parse_dates=['date']
).set_index('date').groupby('region').sum()
return df
# readable and foldable:
def import_data_from_csv_v2(
file_path: str
) -> pd.DataFrame:
"""Read a CSV file and return a DataFrame."""
df = pd.read_csv(
file_path, parse_dates=['date']
).set_index('date').groupby('region').sum()
return df
第二个示例中的缩进清楚地表明了哪些行属于在一起。函数结果的类型注释与参数是函数定义的同等部分。这同样适用于 pandas 方法链接:这只是一个分配,而不是两个。
但是,如果您想通过使用代码折叠来简化模块中的导航,那么不正确的缩进会变得非常烦人。 VS 代码。它根本不适用于该功能的第一个版本!
因此,如果可读性对您很重要,请将多行结构上的右大括号/方括号/括号放在最后一行的第一个非空白字符下,而不是其他任何东西。