68

我想将一个大的 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)

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

有更好的方法吗?

4

10 回答 10

141

首先,玻璃市的一句警句

“如果你有一个有 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)
于 2009-05-03T07:22:58.563 回答
68

您想要一种更好的方式来传递论点,还是只是一种阻止 Pylint 给您带来困难的方式?如果是后者,您可以通过在代码中添加 Pylint 控制注释来停止唠叨:

#pylint: disable=R0913

或更好:

#pylint: disable=too-many-arguments

记住尽快将它们重新打开。

在我看来,传递大量参数并没有任何本质上的错误,主张将它们全部包装在一些容器参数中的解决方案并没有真正解决任何问题,除了阻止 Pylint 唠叨你:-)。

如果你需要传递二十个参数,那么就传递它们。这可能是必需的,因为您的函数做的太多,重构可能会有所帮助,这是您应该考虑的事情。但这不是我们真正可以做出的决定,除非我们看到“真正的”代码是什么。

于 2009-05-03T07:59:40.147 回答
39

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

max-args = 5

至:

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

来自 Pylint 的手册

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

于 2009-05-03T10:58:03.400 回答
11

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

def myfunction(*args):
    for x in args:
        # Do stuff with specific argument here
于 2009-05-03T05:17:42.470 回答
8

也许您可以将一些参数转换为成员变量。如果您需要那么多状态,那么上课对我来说是个好主意。

于 2009-05-03T05:18:05.480 回答
6

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

所以我宁愿这样做:

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

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

所以最好这样做:

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

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

于 2014-11-06T11:31:02.083 回答
6

简化或分解该函数,使其不需要九个参数(或忽略 Pylint,但像您提议的那样躲避 lint 工具的目的)。

如果这是一项临时措施,请使用Pylint 中所述的注释禁用相关特定功能的警告:为块或语句禁用消息?

稍后,您可以使用 grep 查找所有禁用的警告。

于 2009-05-03T05:16:17.853 回答
0

Python 有一些很好的函数式编程工具,很可能很好地满足您的需求。查看lambda 函数map。此外,当您似乎更适合使用列表时,您正在使用 dicts。对于您提供的简单示例,请尝试使用此成语。请注意,地图会更好更快,但可能不适合您的需求:

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)

您提到有很多局部变量,但坦率地说,如果您正在处理列表(或元组),从长远来看,您应该使用列表并排除所有这些局部变量。

于 2009-05-03T05:19:36.130 回答
-1

对于 Python3,您应该只使用关键字参数

文件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)
于 2021-08-11T14:58:37.237 回答
-3

我遇到了同样的唠叨错误,我意识到这与PyCharm自动检测的一个很酷的功能有关……只​​需添加@staticmethod装饰器,它就会自动删除使用该方法的错误。

于 2019-01-05T18:51:50.443 回答