定义带有太多参数的函数以遵守PEP8标准


76

我定义了带有一长串参数的函数。定义的总字符数超过80,并且不遵守PEP8。

def my_function(argument_one, argument_two, argument_three, argument_four, argument_five):

避免水平滚动的最佳方法是什么?


1
编写函数调用语句的最佳方法是什么?:)
Nabin

Answers:


110

PEP 8中给出了一个示例:

class Rectangle(Blob):

    def __init__(self, width, height,
                 color='black', emphasis=None, highlight=0):

这就是官方的答案。我个人讨厌这种方法,在这种方法中,连续行的前导空格不对应任何实际的缩进级别。我的方法是:

class Rectangle(Blob):

    def __init__(
        self, width, height,
        color='black', emphasis=None, highlight=0
    ):

。。。或者只是让该行超过80个字符。


9
我实际上很困惑地在这两者之间进行选择。对于第一个,连续行具有任意空格,这是我不喜欢的。第二个看起来很混乱,很有趣。我希望PEP8官方回答。
Sudip Kafle 2014年

3
我发现您第二个示例中的方法很脏。第一个中的声明引起了我的注意,而第二个中的声明我不得不更加仔细地寻找它。特别是在同一类中有20种方法(每行2-3行)时。
Błażej米哈利克

5
这与变脏无关,这与第二个示例中的方法实际上更实用有关。它允许编辑器对方法主体进行适当的代码折叠,同时允许您查看方法的参数。作者建议的官方数字与任何缩进级别都不对应。
BPL

1
可能有点偏离主题,但是有人知道找到第一个解决方案时是否有办法迫使flake8失败吗?我非常不喜欢它,即使它是标准的PEP8,也更喜欢第二种解决方案。
阿里埃勒

1
如果可以的话,将linter中的“ E128” pep8规则列入黑名单,如果这不能更好地编写您自己的自定义规则@Ariel
Salyangoz,

20

对于使用类型注释的Python代码,我建议这样做:

def some_func(
    foo: str,
    bar: str = 'default_string',
    qux: Optional[str] = None,
    qui: Optional[int] = None,
) -> List[str]:
    """
    This is an example function.
    """
    print(foo)
    ...

如果使用yapf,则可以在.style.yapf以下位置使用这些选项:

[style]
dedent_closing_brackets = true
split_arguments_when_comma_terminated = true

无论您是否使用注释,我都会这样做。它既可维护,也更清晰。
DylanYoung '20

注意:我无法使YAPF符合此样式。我得出的结论是,这是YAPF设计方式的根本问题:箱包装。Bin打包与格式化代码的目的大体相反。
DylanYoung

13

我个人也曾经想出过与@BrenBarn第二种风格相同的解决方案。我喜欢它能正确表示函数参数的缩进及其实现的方式,尽管“不高兴的表情”在某些其他人中并不常见。

如今,PEP8专门提供了这种情况的示例,因此主流可能会采用这种样式:

# More indentation included to distinguish this from the rest.
def long_function_name(
        var_one, var_two, var_three,
        var_four):
    print(var_one)

11
def my_function(argument_one, argument_two, argument_three, 
                argument_four, argument_five):

10

1.我的建议

尽管它使函数更加冗长,但对于多个参数,我认为这是最好的-以下示例来自Python-:

def my_function(
    argument_one, 
    argument_two, 
    argument_three,
    argument_four, 
    argument_five,
):
    ...

2.为什么?

  1. 将每个参数放在一行上使使用git diffs非常简单,因为更改一个变量将仅显示更改。如果您在每一行上有多个参数,那么以后会在视觉上更加烦人。
    • 请注意,最后一个参数之后的尾部逗号使以后添加或删除参数更容易,同时还符合PEP 8的尾部逗号约定,并在git diff以后产生了更好的结果。
  2. 真的不喜欢“使参数与左括号对齐”的原因之一是它不会产生易于维护的代码
    • Kevlin Henney在他的《 ITT 2016-许多程序员的七个无效编码习惯》演讲中(约17:08)解释说这一种不良做法。
    • 不良做法的主要原因是,如果您更改函数的名称(或名称太长),则必须重新编辑所有参数行上的间距,而不是尽管可以(有时)(主观上)更漂亮,但它们都是可扩展的。
    • 与上一个紧密相关的另一个原因是关于元编程。如果代码库太大,您最终会发现自己需要对代码文件本身进行更改编程,如果每个函数的参数间距不同,则可能会陷入困境
  3. 大多数编辑器在打开括号并enter按时会打开带有标签的新行,并将右括号推到下一个未制表的行。因此,以这种方式格式化代码非常快捷且标准化。例如,这种格式在JavaScript和中非常常见Dart
  4. 最后,如果您认为每个参数都太笨拙,因为您的函数可能有很多参数,那么我会说由于极少的例外,您正在损害代码的简易格式。
    • 不要例外立法
    • 如果您的函数有很多参数,则可能是您做错了什么。将其分为更多的(子)功能和(子)类。

3.反正...

好的约定比不好的约定要好,但是强制实施一个约定比对它们不必要地挑剔更为重要

决定使用标准后,与同事分享您的决定并使用自动格式化程序-例如,PrettierJavaScriptin中的流行选择VS Code。并且该Dart语言已在全球范围内标准化:dartfmt—一致地执行它,从而减少了手动编辑的需要。


4

我发现自己这种方式很有趣:

def my_function(
        argument_one, argument_two, argument_three,
        argument_four, argument_five
):
    ...

它允许代码折叠很容易地揭示函数签名,例如,考虑以下代码片段:

def my_function(
        argument_one, argument_two, argument_three,
        argument_four, argument_five
):
    s1 = 1
    s2 = 2
    if s1 + s2:
        s3 = 3


def my_other_function(argument_one, argument_two, argument_three):
    s1 = 1
    s2 = 2
    if s1 + s2:
        s3 = 3

这种方式允许对整个文件进行代码折叠并立即查看所有功能/签名,即:

在此处输入图片说明


3

我个人喜欢以括号括起来并以缩进形式一行一行地排列参数。flake8似乎也对此感到满意。

def guess_device_type(device_name: str,
                      username: str=app.config['KEY_TACACS_USER'],
                      password: str=app.config['KEY_TACACS_PASS'],
                      command: str='show version') -> str:
    """Get a device_type string for netmiko"""

这种样式存在一些技术问题。1)要解析一个功能齐全的模块,眼睛必须不断地移动它水平扫描的位置(除非您所有的函数名称都具有相同的长度;))。2)在之后添加参数command将创建伪造的差异线。3)进入功能块是确定的(这是不直观的,因为在python中,缩进通常会开始一个块)。
DylanYoung '20

1
@DylanYoung,好点!这些天来,我black习惯于自动格式化我的代码。

我也会在任何新代码中使用Black。+1我们的问题主要是迁移旧代码,哈哈。有一天....
DylanYoung '20
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.