我想将一个大的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)
但是这种方法对我来说太丑了,它需要编写很多甚至是多余的代码。
有更好的方法吗?
答案 0 :(得分:86)
首先,Perlis's epigrams之一:
“如果你有一个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)
答案 1 :(得分:35)
您想要一种更好的方式来传递参数,还是只想阻止pylint
给您带来困难?如果是后者,我似乎记得你可以通过pylint
- 在你的代码中控制注释来阻止唠叨:
#pylint: disable-msg=R0913
或:
#pylint: disable-msg=too-many-arguments
记得在切实可行的情况下尽快重新开启。
在我看来,没有什么固有错误传递了很多论点和解决方案主张将它们全部包装在一些容器参数中并没有真正解决任何问题,除了停止{{1}唠叨你: - )。
如果你需要传递20个参数,那么传递它们。可能这是必需的,因为你的功能太多而且重新分解可以帮助那些,这是你应该看的东西。但是,除非我们看到“真正的”代码是什么,否则这不是我们可以做出的决定。
答案 2 :(得分:21)
您可以轻松更改pylint中允许的最大参数数量。只需打开你的pylintrc文件(如果你还没有它就生成它)并更改:
MAX-ARGS = 5
为:
max-args = 6#或任何适合您的值
来自pylint的manual
指定所有合适的选项 为您的设置和编码标准 可能很乏味,所以有可能 使用rc文件指定默认值 值。 Pylint寻找/ etc / pylintrc 和〜/ .pylintrc。 --generate-rcfile 选项将生成评论 根据配置文件 标准的当前配置 输出和退出。你可以把其他 在此之前使用它们的选项 配置,或以。开头 默认值并手动调整 配置。
答案 3 :(得分:12)
您可以尝试使用Python's variable arguments功能:
def myfunction(*args):
for x in args:
# Do stuff with specific argument here
答案 4 :(得分:7)
也许您可以将一些参数转换为成员变量。如果你需要这么多的状态,一个课对我来说听起来不错。
答案 5 :(得分:6)
简化或拆分该函数,使其不需要九个参数(或忽略pylint,但是像你提议的那样闪避一个lint工具的目的)。
编辑:如果是临时措施,请使用此处所述的评论停用相关特定功能的警告:http://lists.logilab.org/pipermail/python-projects/2006-April/000664.html
稍后,您可以查看所有已禁用的警告。
答案 6 :(得分:4)
评论paxdiablo的回复 - 由于我没有足够的声誉直接在那里发表评论: - /
我不喜欢引用这个数字,sybolic名称更具表现力,避免添加可能会随着时间的推移而过时的评论。
所以我宁愿这样做:
#pylint: disable-msg=too-many-arguments
我还建议不要将它悬挂在那里:它将一直保持活动状态,直到文件结束或被禁用,以先到者为准。
做得更好:
#pylint: disable-msg=too-many-arguments
code_which_would_trigger_the_msg
#pylint: enable-msg=too-many-arguments
我还建议每行启用/禁用一个警告/错误。
答案 7 :(得分:0)
Python有一些很好的函数编程工具可能很好地满足您的需求。查看lambda functions和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)
你提到了很多局部变量,但坦率地说,如果你正在处理列表(或元组),你应该使用列表并从长远来看将所有这些局部变量分解出去。
答案 8 :(得分:0)
对于 Python3,您应该只使用 keyword-only arguments:
$ cat 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)
$ cat 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)
答案 9 :(得分:-1)
我遇到了相同的错误,我意识到这与PyCharm自动检测到的一个很酷的功能有关……只需添加@staticmethod装饰器,它将在使用该方法的地方自动删除该错误