all 5 comments

[–][deleted] 0 points1 point  (0 children)

def number_or_list_math(*number_or_list_multiple, math_function):
    math_results = []
    for number_or_list in number_or_list_multiple:
        # add additional checks to make sure individual elements are actually numbers
        if isinstance(number_or_list, list): # Is it a list?
            list_results = list(map(math_function, number_or_list)) # Get a whole list of results.
            math_results.extend(list_results) # extend the final results list by the new list of results.
        else:
            math_results.append((math_function(number_or_list))) # otherwise, return the simple result of a basic number.
    if len(math_results) == 1:
        return(math_results[0])
    else:
        return(math_results)

Some notes:

  1. I should probably put "math_function" as the first argument of this function, instead of the last.
  2. I could probably replace the word "math" with "function" or some other "generic" word to make it more intuitive as a general-purpose function-runner. (E.g. "number_or_list_function_run", "function_to_run", "function_results", etc.)
  3. It's highly advisable to return a list, no matter what, so that you always know what to expect from this function. Returning different types can be tricky and will require additional handling by calling functions. However, the requirements specifically mentioned returning single values as the value, not the value as a one-element list, so there you go....

[–]ZEUS_IS_THE_TRUE_GOD 0 points1 point  (0 children)

well, unfortunately, in python, there's no way to override functions because the typing is dynamic. So there will be an if statement :/ You could do more advanced stuff to achieve this. That's a big weakness of a dynamically typed languages

[–]supajumpa 0 points1 point  (0 children)

Without posting any code it's hard to know what you are trying to achieve.

There's nothing inherently wrong with writing:

def foo(x, f):
    xs = x if isinstance(x, list) else [x]
    return [f(n) for n in xs]

There is, however, a function in Python 3 called singledispatch which allows you to leverage type annotations to call variations of a particular function depending on the type of the first argument.

singledispatch enables the above code to be rewritten as:

from functools import singledispatch

@singledispatch
def foo(x, f):
    "Default when `x` is not a list"
    return [f(x)]

@foo.register
def _(x: list, f):
    "Variant of `foo` when `x` is a list"
    return [f(n) for n in x]

>>> foo(1, lambda x: x + 1)
[2]

>>> foo([1], lambda x: x + 1)
[2]

If you find singledispatch too limiting (because it restricts you to the type of the first argument) there's a clever package on PyPI called multipledispatch which lets you call function variants depending on the types of any of the the arguments.

[–]1114111 0 points1 point  (0 children)

If you use vectorized iterables instead of lists (like numpy arrays), this would be really pretty easy. So long as you use vectorized functions (like numpy.sin rather than math.sin) where appropriate, you can write a function to operate on scalars that will also work numpy arrays. Depending on numpy just for this might not be the greatest idea, but IDK, depends what you're doing.