Python:避免关于太多参数的pylint警告

Ano*_*ous 44 python refactoring pylint

我想将一个大的Python函数重构为较小的函数.例如,请考虑以下代码段:

x = x1 + x2 + x3 + x4 + x5 + x6 + x7 + x8 + x9
Run Code Online (Sandbox Code Playgroud)

当然,这是一个微不足道的例子.在实践中,代码更复杂.我的观点是它包含许多必须传递给提取函数的局部范围变量,它们可能如下所示:

def mysum(x1, x2, x3, x4, x5, x6, x7, x8, x9):
    x = x1 + x2 + x3 + x4 + x5 + x6 + x7 + x8 + x9
    return x
Run Code Online (Sandbox Code Playgroud)

问题是pylint会触发有关太多参数的警告.做以下事情可以避免警告:

def mysum(d):
    x1 = d['x1']
    x2 = d['x2']
    ...
    x9 = d['x9']
    x = x1 + x2 + x3 + x4 + x5 + x6 + x7 + x8 + x9
    return x

def mybigfunction():
    ...
    d = {}
    d['x1'] = x1
    ...
    d['x9'] = x9
    x = mysum(d)
Run Code Online (Sandbox Code Playgroud)

但是这种方法对我来说太丑了,它需要编写很多甚至是多余的代码.

有没有更好的方法呢?

小智 92

首先,玻璃市的一个箴言:

"如果你有一个包含10个参数的程序,你可能会错过一些."

10个论点中的一些可能是相关的.将它们分组为一个对象,然后传递它.

举个例子,因为问题中没有足够的信息可以直接回答:

class PersonInfo(object):
  def __init__(self, name, age, iq):
    self.name = name
    self.age = age
    self.iq = iq
Run Code Online (Sandbox Code Playgroud)

然后你的10个参数函数:

def f(x1, x2, name, x3, iq, x4, age, x5, x6, x7):
  ...
Run Code Online (Sandbox Code Playgroud)

变为:

def f(personinfo, x1, x2, x3, x4, x5, x6, x7):
  ...
Run Code Online (Sandbox Code Playgroud)

并且来电者更改为:

personinfo = PersonInfo(name, age, iq)
result = f(personinfo, x1, x2, x3, x4, x5, x6, x7)
Run Code Online (Sandbox Code Playgroud)

  • 我喜欢这个答案,因为它指出了如何思考这个问题! (9认同)
  • 请注意,从 Python 2.6 开始,您可以使用 collections.namedtuple 代替类来执行完全相同的操作。 (2认同)
  • 最终,最好的答案是满足OP需求的答案,但是这当然应该被选择,因为其他答案告诉您如何绕过警告,而这个答案告诉您如何重组参数以满足作者的需求。 (2认同)

pax*_*blo 41

你想要一个更好的方法来传递参数,或者只是一种方法来阻止pylint你给你带来困难吗?如果是后者,我似乎记得你可以通过pylint在代码中按照以下方式放置控制注释来阻止唠叨:

#pylint: disable-msg=R0913
Run Code Online (Sandbox Code Playgroud)

要么:

#pylint: disable-msg=too-many-arguments
Run Code Online (Sandbox Code Playgroud)

记得在切实可行的情况下尽快将它们重新打开.

在我看来,传递大量论据并没有什么本质上的错误,并且主张在一些容器论证中包装它们的解决方案并没有真正解决任何问题,除了pylint不要唠叨你:-).

如果你需要传递20个参数,那么传递它们.可能这是必需的,因为你的功能太多而且重新分解可以帮助那些,这是你应该看的东西.但它不是一个决定,我们真的可以,除非我们看到了"真实"的代码是什么.

  • 这个答案鼓励真正的坏习惯 - 现在在2015年阅读.1)用他们的号码禁用检查 - 现代的pylint版本支持符号描述符,更多的解释2)禁用某些东西也应该有一个注释,并解释为什么它被禁用3 )每行应该只有一个指令,通过相应的重新启用来平衡4)通常pylint确实有一个点.与这些限制冲突的代码可能不可读/不可维护.5)使用字典或命名元组要好得多,而不是传递大量参数. (4认同)
  • 伊戈尔,这就是我说"沿着这条线"的原因.通过各种方式使用符号而不是数字,或每行一个,或注释为什么,或重新启用(虽然你应该考虑这意味着如果以前被禁用 - 更好的是保存/禁用/恢复的方法).这些都不会改变答案本身的效用,即告诉pylint停止警告用户_knows_他们不想听到的问题(并接受后果). (4认同)
  • 从2017年开始(pylint`1.6.5`),`disable-msg`和`enable-msg`现在已被弃用。您应该只使用“禁用”和“启用”(符号描述适用于这些功能)。 (3认同)
  • 用户最有可能经常处于自相矛盾之中:在这种意义上,pylint并不是最明确的工具,但所提供的警告通常具有比消息似乎提供的更深的范围.因此,用户可能*认为*知道接受了什么后果,但是他没有完全理解其含义. (2认同)
  • 无论是好习惯还是坏习惯,这就是问题的答案! (2认同)

Nad*_*mli 24

您可以轻松更改pylint中允许的最大参数数量.只需打开你的pylintrc文件(如果你还没有它就生成它)并更改:

MAX-ARGS = 5

至:

max-args = 6#或任何适合您的值

从pylint的手册

指定适合您的设置和编码标准的所有选项可能很繁琐,因此可以使用rc文件指定默认值.Pylint查找/ etc/pylintrc和〜/ .pylintrc.--generate-rcfile选项将根据标准输出和退出的当前配置生成注释配置文件.您可以在此配置之前添加其他选项以在配置中使用它们,或者从默认值开始并手动调整配置.

  • @Derek pylintrc 应该与其余代码一起进行版本控制 (6认同)

hbw*_*hbw 12

您可以尝试使用Python的变量参数功能:

def myfunction(*args):
    for x in args:
        # Do stuff with specific argument here
Run Code Online (Sandbox Code Playgroud)


Bri*_*sen 8

也许您可以将一些参数转换为成员变量.如果你需要这么多的状态,一个课对我来说听起来不错.

  • 不,但是如果您提取新类型,则可以将某些状态转换为成员变量. (4认同)

Tom*_*zky 7

对于 Python 3,您应该只使用仅关键字参数

文件pylint_args_too_many.py

"""Example of a function causing pylint too-many-arguments"""


def get_car(
    manufacturer, model, year=None, registration_number=None, vin=None, color=None
):
    """Returns dict with all required car attributes"""
    return {
        "manufacturer": manufacturer,
        "model": model,
        "year": year,
        "registration_number": registration_number,
        "vin": vin,
        "color": color,
    }


print(repr(get_car(manufacturer="ACME", model="Rocket")))
Run Code Online (Sandbox Code Playgroud)
"""Example of a function causing pylint too-many-arguments"""


def get_car(
    manufacturer, model, year=None, registration_number=None, vin=None, color=None
):
    """Returns dict with all required car attributes"""
    return {
        "manufacturer": manufacturer,
        "model": model,
        "year": year,
        "registration_number": registration_number,
        "vin": vin,
        "color": color,
    }


print(repr(get_car(manufacturer="ACME", model="Rocket")))
Run Code Online (Sandbox Code Playgroud)

文件pylint_args.py

"""Show how to avoid too-many-arguments"""


def get_car(
    *, manufacturer, model, year=None, registration_number=None, vin=None, color=None
):
    """Returns dict with all required car attributes"""
    return {
        "manufacturer": manufacturer,
        "model": model,
        "year": year,
        "registration_number": registration_number,
        "vin": vin,
        "color": color,
    }


print(repr(get_car(manufacturer="ACME", model="Rocket")))
Run Code Online (Sandbox Code Playgroud)
pylint pylint_args_too_many.py

************* Module pylint_args_too_many
pylint_args_too_many.py:4:0: R0913: Too many arguments (6/5) (too-many-arguments)

------------------------------------------------------------------
Your code has been rated at 6.67/10 (previous run: 6.67/10, +0.00)
Run Code Online (Sandbox Code Playgroud)


Dav*_*ave 6

简化或分解函数,使其不需要九个参数(或忽略pylint,但像你提议的那样闪避一个lint工具的目的).

编辑:如果这是一个临时措施,请使用此处所述的评论禁用相关特定功能的警告:http://lists.logilab.org/pipermail/python-projects/2006-April/000664.html

稍后,您可以查看所有已禁用的警告.


Igo*_*ppa 6

我不喜欢引用数字,符号名称更具表现力,并且避免添加可能会随着时间的流逝而过时的注释。

所以我宁愿这样做:

#pylint: disable-msg=too-many-arguments
Run Code Online (Sandbox Code Playgroud)

而且我还建议不要让它悬在那里:它会一直保持活动状态,直到文件结束或被禁用,以先到者为准。

所以更好地做:

#pylint: disable-msg=too-many-arguments
code_which_would_trigger_the_msg
#pylint: enable-msg=too-many-arguments    
Run Code Online (Sandbox Code Playgroud)

我还建议每行启用/禁用一个警告/错误。