I hope you are well in these trying times.
You are right that this rule is about brain overload, that calling a method/function with too many positional parameters is difficult to understand, and that naming them makes it better.
I feel however that we might be mixing two different things here: function definition and function call. After reading your post a few questions came to my mind, the first one being…
1/ Is the rule raising false positives?
Before going for a specific solution, let’s first clarify the problem. I took a look at how this rule behaves on some well known open-source projects. The maximum number of parameters was left to its default value, i.e. max 7 parameters. Some projects had less than 10 issues but many big projects (pandas, scikit-learn, tensorflow) had more than 100. Raising that many issues indicates that there is clearly a problem with either the pattern detected by rule S107, or its default configuration.
2/ Would Ignoring keyword-only parameters solve the problem?
Let’s see if keyword-only parameters should be ignored. We can do this by digging a bit in these open-source projects and see if they use keyword-only arguments.
It seems that we would still raise most issues if we ignored keyword-only parameters. This makes sense as many projects still had to support python 2 in 2019. I doubt that they will change their APIs anytime soon.
3/ Are there alternative solutions?
I did a rapid search to see how the 34-parameter-initializer of Tornado is used. Developers have the common sense of passing arguments by name rather than position. We probably don’t have to force them to do it. Actually, keyword only arguments were not created to enforce the use of named arguments. They were added to improve the use of varargs. Of course there are other benefits such as the impossibility to pass an argument as positional and keyword at the same time.
This also matches python philosophy: “We are all responsible users”. Developers are not expected to go out of their way to forbid improper use of a feature.
So how do we make sure that:
- We don’t raise False Positives with this rule, i.e. everybody agrees that the pattern it detects is wrong.
- This rule works out of the box for most people, the few remaining projects just have to configure it.
- This rule is simple to understand and to follow (as Zen of python says “Simple is better than complex.”)
Maybe we could consider that the problem of passing too many positional arguments to a function call is a separate problem.
I suggest the following:
- For rule S107:
- Set the default value for the maximum number of parameters to a higher value. I don’t know which value yet, this needs to be tested. I would be interested in knowing the type of project you work on and the max number of parameters you would use.
- Improve the description to make it clear that this rule does not focus on how the method is called, but rather how it is designed and how well it is understood by developers. Something along the lines of:
Python functions and methods methods should not have too many parameters, even if they have default values, because:
- it makes their signature difficult to read and document. You can group parameters into structures to make relations between them clearer.
- a function with many parameters usually does too many things. If this is the case you should probably refactor the code into multiple functions/classes/methods, each having clear responsibilities.
This rule raises an issue when a function or method has too many parameters.
- Add a separate rule to detect when developers call a method or a function with too many positional parameters. It would recommend to pass these parameters by name.
- I am interested in the maximum number of parameters you would use.
We can also envision a rule which recommends the use of keyword only parameters when a function has too many parameters with default values. However this rule would have to be optional as it would raise many issues on Django and other well known projects. We first need to check if it is a best practice or not. All opinions on the matter are welcome.
Does it make sense to you? Feel free to point any flaw in my reasoning or suggest other solutions.