Spinor8
Spinor8

Reputation: 1607

Decorator approach to function polymorphism in Python 3

I have a function f that takes in the arguments i, A and B. i is a counter and A and B are lists or constants. The function just adds the i-th element of A and B if they are lists. Here's what I have written in Python 3.

def const_or_list(i, ls):
    if isinstance(ls, list):
        return ls[i]
    else:
        return ls

def f(i, A, B):
    _A = const_or_list(i, A)
    _B = const_or_list(i, B)
    return _A + _B

M = [1, 2, 3]
N = 11
P = [5, 6, 7]
print(f(1, M, N)) # gives 13
print(f(1, M, P)) # gives 8

You will notice that const_or_list() function is called on two (but not all) of the input arguments. Is there a decorator (presumably more Pythonic) approach to achieve what I am doing above?

Upvotes: 1

Views: 1040

Answers (2)

Stephen Rauch
Stephen Rauch

Reputation: 49812

I think more pythonic in this case is not with a decorator. I would get rid of the isinstance, use a try/except instead and get rid of the intermediate variables:

Code:

def const_or_list(i, ls):
    try:
        return ls[i]
    except TypeError:
        return ls

def f(i, a, b):
    return const_or_list(i, a) + const_or_list(i, b)

Test Code:

M = [1, 2, 3]
N = 11
P = [5, 6, 7]
Q = (5, 6, 7)
print(f(1, M, N))  # gives 13
print(f(1, M, P))  # gives 8
print(f(1, M, Q))  # gives 8

Results:

13
8
8

But I really need a decorator:

Fine, but it is a lot more code...

def make_const_or_list(param_num):
    def decorator(function):
        def wrapper(*args, **kwargs):
            args = list(args)
            args[param_num] = const_or_list(args[0], args[param_num])
            return function(*args, **kwargs)
        return wrapper
    return decorator

@make_const_or_list(1)
@make_const_or_list(2)
def f(i, a, b):
    return a + b

Upvotes: 1

Pavan
Pavan

Reputation: 108

You can do:

def const_or_list(i, ls):
    if isinstance(ls, list):
        return ls[i]
    else:
        return ls

def f(*args):
    i_ip = args[0]
    result_list = []
    for i in range(1, len(args)):
        result_list.append(const_or_list(i_ip, args[i]))
    return sum(result_list)

M = [1, 2, 3]
N = 11
P = [5, 6, 7]
print(f(1, M, N)) # gives 13
print(f(1, M, P)) # gives 8

Upvotes: 0

Related Questions