开发者

Way to Treat Python single vals and lists of vals identically?

开发者 https://www.devze.com 2023-01-07 06:54 出处:网络
I\'m running into this problem often:I\'m creating a function that needs to perform a series of operations on a value, whether that value be a single value or a list of values.

I'm running into this problem often: I'm creating a function that needs to perform a series of operations on a value, whether that value be a single value or a list of values.

Is there an elegant way to do this:

def convert_val(val):
   do a series o开发者_开发知识库f things to each value, whether list or single val
   return answer or list of answers

rather than what I've been doing?:

def convert_val(val):
    if isinstance(val, list):
       ... do a series of things to each list item,
       return a list of answers
    else:
       ... do the same series, just on a single value
       return a single answer

One solution would be to create a sub_convert() that would do the series of actions, and then just call it once or iteratively, depending on the type passed in to convert().

Another would be to create a single convert() that would accept the arguments (value, sub_convert()).

Other suggestions that would be more compact, elegant and preferably all in one function?

(I've done several searches here to see if my issue has already been addressed. My appologies if it has.)

Thanks, JS


You need to fix your design to make all uses of the function actually correct.

Ralph Waldo Emerson. "A foolish consistency is the hobgoblin of little minds, adored by little statesmen and philosophers and divines."

We're not talking about a foolish consistency. You have what might be a design problem based on inconsistent use of this function.

Option 1. Don't call convert_val( x ) where x is a non-list. Do this. convert_val( [x] ). Don't fix your function, fix all the places that use your function. Consistency helps reduce bugs.

Option 2. Change the design of convert_val to use multiple positional arguments. This doesn't generalize well.

def convert_val( *args ):
    whatever it's supposed to do to the arguments.

Then fix all the places you provide a list to be convert_val( *someList ). That's okay, and may be closer to your intent.

Note.

You can find your design errors using the warnings module.

def convert_val( arg ):
    if isinstance( arg, collections.Sequence ):
        return convert_val_list( arg )
    else:
        warnings.warn( "Fix this" )
        return convert_val_list( [arg] )[0]

def convert_val_list( arg ):
    assert isinstance( arg, collections.Sequence )
    the original processing

Once you've fixed all the design problems, you can then do this

convert_val = convert_val_list

And delete the original function.


If the function makes sense for a single value, as well as for a list, then logically the function's result for a certain list item will not depend on the other items in the list.

For example, a and b should end up identical:

items = [1, 2]
a = convert_val(items)
b = map(convert_val, items)

This example already hints at the solution: the caller knows whether a list or a single value is passed in. When passing a single value, the function can be used as-is. When passing a list, a map invocation is easily added, and makes it clearer what's happening on the side of the caller.

Hence, the function you describe should not exist in the first place!


I'm late to the party here and I'm not sure if this is what OP wants.

I much prefer to keep the implementation details hidden inside the function. The caller shouldn't care about what happens inside.

def convert_val(val):
    values = []
    values.extend(val)
    for value in values:
        # do things to each list item,
    return a list of answers

This would make the convert_val put val into the values list (if not a list) or all values of val into the values list.

In addition should predictably get a list back (since you'd be using the same logic).

In the end:

assert convert_val([1]) == convert_val(1)
0

精彩评论

暂无评论...
验证码 换一张
取 消