【问题标题】:Define functions with too many arguments to abide by PEP8 standard定义具有太多参数的函数以遵守 PEP8 标准
【发布时间】:2014-09-19 05:20:34
【问题描述】:

我定义了一个带有一长串参数的函数。定义总字数80以上,不遵守PEP8。

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

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

【问题讨论】:

  • 编写函数调用语句的最佳方法是什么? :)
  • 这里各种各样的答案强化了这样一个事实,即您应该就一种风格与您的团队达成一致并坚持下去!

标签: python pep8


【解决方案1】:
def my_function(argument_one, argument_two, argument_three, 
                argument_four, argument_five):

【讨论】:

    【解决方案2】:

    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 个字符。

    【讨论】:

    • 我实际上很困惑在这两者之间进行选择。对于第一个,连续线具有任意空格,这是我不喜欢的。第二个看起来令人困惑,因为它是一个功能。我更喜欢 PEP8 官方答案。
    • 我发现您的第二个示例中的方法很脏。第一个声明引起了我的注意,没有问题,而第二个声明我必须仔细观察才能找到它。尤其是当同一个类中有 20 个方法,每个方法 2-3 行时。
    • 这不是关于或多或少的肮脏,这是关于第二个示例的方法实际上更实用。它允许编辑器对方法体进行适当的代码折叠,同时允许您查看方法的参数。作者建议的官方版本不对应任何缩进级别。
    • 可能有点跑题了,但是有没有人知道是否有办法迫使 flake8 在找到第一个解决方案时失败?我真的不喜欢它,即使它是标准 PEP8 并且更喜欢第二种解决方案。
    • 如果可以,请将 linter 中的“E128”pep8 规则列入黑名单,如果这样写自己的自定义规则效果不好@Ariel
    【解决方案3】:

    我个人也曾经提出与@BrenBarn 的第二种风格相同的解决方案。我喜欢它正确表示函数参数的缩进及其实现的方式,尽管“不开心的脸”对其他人来说有些不寻常。

    现在PEP8专门给出了这样的例子,所以也许主流会适应这种风格:

        # Add 4 spaces (an extra level of indentation)
        # to distinguish arguments from the rest.
        def long_function_name(
                var_one, var_two, var_three,
                var_four):
            print(var_one)
    

    我们当然可以更进一步,将每个参数分开到自己的行中,这样以后任何添加/删除参数都会得到一个干净的git diff

        # Add 4 spaces (an extra level of indentation)
        # to distinguish arguments from the rest.
        def long_function_name(  # NOTE: There should be NO parameter here
                var_one,
                var_two,
                var_three,
                var_four,  # NOTE: You can still have a comma at the last line
                ):  # NOTE: Here it aligns with other parameters, but you could align it with the "def"
            print(var_one)
    

    【讨论】:

      【解决方案4】:

      对于使用 type annotations 的 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
      

      如果你使用black,你不需要做任何事情,如果你在最后一个参数后面添加一个逗号,它会使用上面的样式。

      【讨论】:

      • 无论您是否使用注释,我都会这样做。它更易于维护,也更易读。
      • 注意:我无法让 YAPF 符合这种风格。我得出的结论是,这是 YAPF 设计方式的一个根本问题:装箱。 Bin 打包在很大程度上与您想要格式化代码的方式相反。
      • 这对我来说仍然很奇怪,但它是我见过的替代品中我最喜欢的。唯一的问题是它不能很好地与没有文档字符串的函数体分开,但这也让我更有可能包含我应该做的文档字符串
      【解决方案5】:

      我个人喜欢将参数排成一行,从左括号开始并保持缩进。 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,好点!这些天来,我使用black 来自动格式化我的代码。
      • 我也会在任何新代码中使用黑色。 +1 我们的问题主要是关于迁移旧代码,哈哈。总有一天……
      【解决方案6】:

      我发现自己这样做很有趣:

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

      它允许代码折叠很容易地揭示函数签名,例如,考虑下面的 sn-p:

      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
      

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

      【讨论】:

        【解决方案7】:

        1。我会推荐什么

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

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

        2。为什么?

        1. 将每个参数放在一行中使得使用git diffs 变得非常简单,因为更改一个 变量只会显示 的更改。如果每一行都有不止一个论点,那么以后在视觉上会更烦人。
          • 请注意,最后一个参数后面的逗号使以后添加或删除参数更容易,同时也符合PEP 8's Trailing Comma Convention,并在以后产生更好的git diff
        2. 真的不喜欢“将参数与左括号对齐”范例的原因之一是它不会产生易于维护的代码
          • Kevlin Henney 在his ITT 2016 - Seven Ineffective Coding Habits of Many Programmers lecture (around 17:08) 中解释说 是一种不好的做法。
          • 这是一种不好的做法的主要原因是,如果您更改函数的名称(或者如果它太长),您将不得不重新编辑 all上的间距> 论点的线条,完全不可扩展,虽然它可能 (sometimes) (subjectively) 更漂亮。
          • 另一个与上述原因密切相关的原因是关于元编程。如果代码库变得太大,您最终会发现自己需要对代码文件本身进行编程更改,如果每个函数的参数间距不同,这可能会变得地狱
        3. 大多数编辑器,一旦打开括号并按下 enter,将打开一个带有制表符的新行,并将右括号推到下一行,没有制表符。因此,以这种方式格式化代码非常快速且标准化。例如,这种格式在JavaScriptDart 中很常见。
        4. 最后,如果您认为每个参数都过于笨拙,因为您的函数可能有 很多 个参数,我会说您因为极少数例外而影响了代码的简单格式化。
          • 不要通过例外来立法
          • 如果您的函数有 很多 个参数,那么您可能做错了什么。将其分解为更多(子)函数和(子)类。

        3。无论如何...

        一个好的约定比一个坏的要好,但是执行一个比不必要地挑剔它们更重要

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

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-09-01
          • 2012-08-25
          相关资源
          最近更新 更多