Unpack without using * (asterisk)

688 Views Asked by At

If I want to keep things functional, and do not want to use * in the middle, then what is the equivalent substitute function? for example,

import operator as op
print(op.eq(*map(str.upper, ['a', 'A'])))

how do I avoid using * here?

I created a function, like,

def unpack(args):
  return *args

but it gives syntax error, print(*args) works but return fails

4

There are 4 best solutions below

1
On BEST ANSWER

One way to achieve this is by creating a function named apply.

def apply(func, args):
    return func(*args)
apply(op.eq, map(str.upper, ['a', 'A']))
0
On

functools.reduce can be used to apply a function of two arguments to an iterable cumulatively, which would work for your example case

import operator as op
from functools import reduce
print(reduce(op.eq, map(str.upper, ['a', 'A'])))
0
On

You could use reduce to check if all of the mapped elements are equal to each other.

from functools import reduce
print(reduce(op.eq, map(str.upper, ['a', 'A'])))

This isn't really a sensible thing to do, though. I say this because the reduce call above doesn't generalize to cases with more or fewer elements:

  • If the input were empty it would fail with TypeError: reduce() of empty sequence with no initial value.
  • If it were given a one-item input list it would return a string rather than a boolean True or False.
  • If it were given list with 3+ items it would end up comparing strings to booleans and would always result in False.

If your plan is to call op.eq with exactly two operands, no more and no less, then unpacking with * is appropriate. Even in a functional context.

0
On

You can solve this with reduce if there is some safe value you know will not occur. For example, if you know None will not be in your list, you can do

import functools
mylist = list(map(str.upper, ['a', 'A']))
result = functools.reduce(lambda x, y: x if x == y else None, mylist)
print('all equal' if result != None else 'some differ')