Python: avoiding Pylint warnings about too many arguments
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?
Solution 1:
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)
Solution 2:
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.
Solution 3:
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.