避免关于太多参数的 Pylint 警告

我想把一个大的 Python 函数重构成更小的函数:

x = x1 + x2 + x3 + x4 + x5 + x6 + x7 + x8 + x9

当然,这是一个微不足道的例子。实际上,代码更加复杂。我的观点是,它包含许多必须传递给提取函数的局部作用域变量,这些变量可能类似于:

def mysum(x1, x2, x3, x4, x5, x6, x7, x8, x9):
x = x1 + x2 + x3 + x4 + x5 + x6 + x7 + x8 + x9
return x

问题是,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)

但是这种方法对我来说很丑陋,它需要编写大量的代码,甚至是多余的。

还有更好的办法吗?

142922 次浏览

简化或者分解函数,使其不需要9个参数(或者忽略 Pylint,但是回避你提议的那些参数会破坏 lint 工具的作用)。

如果这是一个临时措施,那么使用 Pylint: 禁用块或语句的 msg中描述的注释禁用特定函数的警告

稍后,您可以对所有禁用警告进行 grep。

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

def myfunction(*args):
for x in args:
# Do stuff with specific argument here

也许您可以将一些参数转换为成员变量。如果你需要那么多的状态,一个类听起来像是一个好主意。

Python 有一些很好的函数式编程工具,可能很适合您的需要。看看 Lambda 函数地图。而且,当你觉得列表更适合你的时候,你也在使用口令。对于您提供的简单示例,请尝试使用这个习语。请注意,地图会更好,更快,但可能不适合您的需要:

def mysum(d):
s = 0
for x in d:
s += x
return s


def mybigfunction():
d = (x1, x2, x3, x4, x5, x6, x7, x8, x9)
return mysum(d)

您提到有很多本地变量,但坦率地说,如果您处理列表(或元组) ,您应该使用列表并且从长远角度考虑所有这些本地变量。

首先,Perlis 的警句中的一个:

"If you have a procedure with 10 参数,你可能漏掉了一些。”

这10个参数中的一些可能是相关的。将它们分组到一个对象中,然后传递该对象。

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

class PersonInfo(object):
def __init__(self, name, age, iq):
self.name = name
self.age = age
self.iq = iq

然后是你的10个参数函数:

def f(x1, x2, name, x3, iq, x4, age, x5, x6, x7):
...

变成:

def f(personinfo, x1, x2, x3, x4, x5, x6, x7):
...

来电显示为:

personinfo = PersonInfo(name, age, iq)
result = f(personinfo, x1, x2, x3, x4, x5, x6, x7)

您是想要一种更好的方法来传递参数,还是仅仅想要一种方法来阻止 Pylint 为难您?如果是后者,您可以通过在代码中添加控制 Pylint 的注释来停止唠叨:

#pylint: disable=R0913

或者,更好的办法是:

#pylint: disable=too-many-arguments

记得在可行的情况下尽快把它们打开。

在我看来,传递大量的参数和解决方案并没有什么错,这些参数和解决方案主张将它们全部包装在一些容器参数中并不能真正解决任何问题,除了阻止 Pylint 烦扰您之外: ——)。

如果你需要传递20个参数,那么就传递它们。这可能是因为您的函数执行的操作太多,所以需要这样做 重构可以帮助解决这个问题,这也是你应该关注的。但是,除非我们看到“真正的”代码是什么,否则 我们无法真正做出这样的决定。

你可以很容易地改变在 Pylint 允许的最大参数数量。打开你的 Pylintrc文件(如果你还没有的话就生成它)然后修改:

max-args = 5

致:

max-args = 6 # Or any value that suits you

来自皮林特的 手动操作

指定所有适当的选项 为您的设置和编码标准 可能是乏味的,所以有可能 使用 rc 文件指定默认值 Pylint 查找/etc/pylintrc 和 ~/. pylintrc. —— create-rcfile 选项将生成一个注释 配置文件 标准电流配置 输出和退出 选项之前,这一个使用它们 配置,或者从 默认值并手动调优 配置。

我不喜欢提到这个数字。符号名更具表现力,并且避免了添加可能随着时间推移而过时的注释。

所以我宁愿这样做:

#pylint: disable-msg=too-many-arguments

我还建议不要让它悬挂在那里: 它将保持活动状态,直到文件结束或禁用,无论哪一个先出现。

所以最好这样做:

#pylint: disable-msg=too-many-arguments
code_which_would_trigger_the_msg
#pylint: enable-msg=too-many-arguments

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

我遇到了同样的纠缠错误,我意识到这与一个很酷的特性 PyCharm自动检测有关... 只要添加 @staticmethod修饰器,它就会自动删除使用该方法的地方的错误。

对于 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 dict(
manufacturer=manufacturer,
model=model,
year=year,
registration_number=registration_number,
vin=vin,
color=color,
)


print(repr(get_car(manufacturer="ACME", model="Rocket")))
pylint pylint_args_too_many.py


************* Module pylint_args_too_many
pylint_args_too_many.py:3: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)

文件 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 dict(
manufacturer=manufacturer,
model=model,
year=year,
registration_number=registration_number,
vin=vin,
color=color,
)


print(repr(get_car(manufacturer="ACME", model="Rocket")))
pylint pylint_args.py


--------------------------------------------------------------------
Your code has been rated at 10.00/10 (previous run: 10.00/10, +0.00)

使用 数据类:

from dataclasses import dataclass


# declare your data structure
@dataclass
class Struct:
x1: int
x2: int
x3: int
x4: int
x5: int


# declare your function operating on this structure
def mysum(s: Struct):
return s.x1 + s.x2 + s.x3 # ...


def mybigfunction():
s = Struct(1,2,3,4,5) # instantiate your structure
x = mysum(s)
return x

然后 mybigfunction()返回 6(1 + 2 + 3)。

这是一种分组、组织和记录参数的好方法,也简化了函数的类型提示。

请注意,dataclass装饰器所做的一切都是通过实现 __init__方法和其他方法使您的工作变得更容易。