Is there any way to reduce number of arguments in a function without much refactoring the original function?

Question:

This question is related to Python: avoiding Pylint warnings about too many arguments

I have a function, which has many arguments. The highest vote answer in the above link suggests using a class as the argument. But, then, I need to work a bit on the original function to adapt the new argument as a class.

For example,

def operator(a, b, c, d, e, f, o):
    if o == 'a':
        return a + b + c + d + e + f
    if o == 'b':
        return a + b + d + d + e - f 

I can introduce a class

class input_entry:
    def __init__(self, a, b, c, d, e, f):
        self.a = a
        self.b = b    
        self.c = c    
        self.d = d    
        self.e = e    
        self.f = f    

input_item = input_entry(1,2,3,4,5,6)

then I need a revised function,

def operator_v2(input_item, o):
    a = input_item.a
    b = input_item.b
    c = input_item.c
    d = input_item.d
    e = input_item.e
    f = input_item.f

    if o == 'a':
        return a + b + c + d + e + f
    if o == 'b':
        return a + b + d + d + e - f    

Is there any shortcut from operator to operator_v2? In general, the arguments can be complicated, putting many entries into a list may be less suitable than introducing the class. (This example may not be ideal, since the class input_entry still have many arguments)

Asked By: Chungji

||

Answers:

With @dataclass you have a lot less code duplication, and less boilerplate in order to reuse your original operator definition:

from dataclasses import astuple, dataclass

@dataclass
class Operands:
    a: int
    b: int
    c: int
    d: int
    e: int
    f: int

def operator(operands: Operands, o: str) -> int:
    a, b, c, d, e, f = astuple(operands)
    if o == 'a':
        return a + b + c + d + e + f
    if o == 'b':
        return a + b + d + d + e - f

print(operator(Operands(1, 2, 3, 4, 5, 6), 'a'))  # 21
Answered By: Samwise

Not exactly sure what you’re doing (or why), and it’s unclear if your input is numbers or characters, but here is an example of a function accepting a variable number of arguments and assumes the first param is o, then assumes a is the first element of arg (arg[0]) and likewise b is the second. It further assumes that f is the last arg (and any number of args can be passed so long as several else you’ll need more validation / error handling. A default return value needs to be determined also.

def operator_v3(o, *args):
    if o == args[0]:
        return sum(x for x in args)
    if o == args[1]:
        return sum(x for x in args[:-1]) - args[-1]

    # need to specify default
    return o

a = operator_v3(1,1,2,3,4,5,6)  # o == a
b = operator_v3(1,1,1,3,4,5,6)  # o == b

print(f"a = {a}")  # a = 21
print(f"b = {b}")  # b = 20

You could also easily make the last arg o and then not have to change any of your existing function calls since the signature remains the same essentially.

Answered By: Dan
Categories: questions Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.