Python:避免 Pylint 关于参数过多的警告

发布于 2024-07-18 21:10:36 字数 709 浏览 7 评论 0原文

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

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

有更好的方法吗?

I want to refactor a big Python function into smaller ones. For example, consider this following code snippet:

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

Of course, this is a trivial example. In practice, the code is more complex. My point is that it contains many local-scope variables that would have to be passed to the extracted function, which could look like:

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

The problem is that Pylint would trigger a warning about too many arguments.

I could avoid the warning by doing something like:

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)

but this approach loos ugly to me. It requires writing a lot of code that is even redundant.

Is there a better way to do it?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(11

べ映画 2024-07-25 21:10:36

首先,玻璃市的警句之一:

“如果您有一个包含 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)

First, one of Perlis's epigrams:

"If you have a procedure with 10
parameters, you probably missed some."

Some of the 10 arguments are presumably related. Group them into an object, and pass that instead.

Making an example up, because there's not enough information in the question to answer directly:

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

Then your 10 argument function:

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

becomes:

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

and the caller changes to:

personinfo = PersonInfo(name, age, iq)
result = f(personinfo, x1, x2, x3, x4, x5, x6, x7)
夏九 2024-07-25 21:10:36

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

#pylint: disable=R0913

或者更好的是:

#pylint: disable=too-many-arguments

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

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

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

Do you want a better way to pass the arguments or just a way to stop Pylint from giving you a hard time? If the latter, you can stop the nagging by putting Pylint-controlling comments in your code along the lines of:

#pylint: disable=R0913

or, better:

#pylint: disable=too-many-arguments

remembering to turn them back on as soon as practicable.

In my opinion, there's nothing inherently wrong with passing a lot of arguments and solutions advocating wrapping them all up in some container argument don't really solve any problems, other than stopping Pylint from nagging you :-).

If you need to pass twenty arguments, then pass them. It may be that this is required because your function is doing too much
and refactoring could assist there, and that's something you should look at. But it's not a decision we can really make unless we see what the 'real' code is.

无畏 2024-07-25 21:10:36

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

max-args = 5

为:

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

来自 Pylint 的 手册

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

You can easily change the maximum allowed number of arguments in Pylint. Just open your pylintrc file (generate it if you don't already have one) and change:

max-args = 5

to:

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

From Pylint's manual

Specifying all the options suitable
for your setup and coding standards
can be tedious, so it is possible to
use a rc file to specify the default
values. Pylint looks for /etc/pylintrc
and ~/.pylintrc. The --generate-rcfile
option will generate a commented
configuration file according to the
current configuration on standard
output and exit. You can put other
options before this one to use them in
the configuration, or start with the
default values and hand tune the
configuration.

醉城メ夜风 2024-07-25 21:10:36

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

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

You could try using Python's variable arguments feature:

def myfunction(*args):
    for x in args:
        # Do stuff with specific argument here
又怨 2024-07-25 21:10:36

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

Perhaps you could turn some of the arguments into member variables. If you need that much state a class sounds like a good idea to me.

筑梦 2024-07-25 21:10:36

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

文件 < em>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")))
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)

文件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")))
pylint pylint_args.py

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

For Python 3, you should just use keyword-only arguments:

File 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")))
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)

File 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")))
pylint pylint_args.py

--------------------------------------------------------------------
Your code has been rated at 10.00/10 (previous run: 10.00/10, +0.00)
执手闯天涯 2024-07-25 21:10:36

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

所以我宁愿这样做:

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

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

所以最好这样做:

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

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

I do not like referring to the number. The symbolic name is much more expressive and avoid having to add a comment that could become obsolete over time.

So I'd rather do:

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

And I would also recommend to not leave it dangling there: it will stay active until the file ends or it is disabled, whichever comes first.

So better do:

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

I would also recommend enabling/disabling one single warning/error per line.

冷心人i 2024-07-25 21:10:36

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

如果这是临时措施,请使用注释禁用有关特定函数的警告,如 Pylint: 为块或语句禁用消息?

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

Simplify or break apart the function so that it doesn't require nine arguments (or ignore Pylint, but dodges like the ones you're proposing defeat the purpose of a lint tool).

If it's a temporary measure, disable the warning for the particular function in question using a comment as described in Pylint: Disable-msg for a block or statement?

Later, you can grep for all of the disabled warnings.

稀香 2024-07-25 21:10:36

使用 dataclass

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__ 方法和其他方法来使您的工作更轻松。

Use a dataclass:

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

Then mybigfunction() returns 6 (1+2+3).

This is a nice way to group, organize, and document your arguments. It also simplifies type hinting of functions.

Note that all the dataclass decorator does is making your work easier by implementing the __init__ method and others.

终难愈 2024-07-25 21:10:36

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)

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

Python has some nice functional programming tools that are likely to fit your needs well. Check out lambda functions and map. Also, you're using dicts when it seems like you'd be much better served with lists. For the simple example you provided, try this idiom. Note that map would be better and faster but may not fit your needs:

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)

You mentioned having a lot of local variables, but frankly if you're dealing with lists (or tuples), you should use lists and factor out all those local variables in the long run.

神回复 2024-07-25 21:10:36

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

I came across the same nagging error, which I realized had something to do with a cool feature PyCharm automatically detects...just add the @staticmethod decorator, and it will automatically remove that error where the method is used.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文