Search code examples
pythoniteratorlist-comprehensionmultiple-resultsets

How can a function return a dynamic value that depends on the number of receivers in Python?


I was trying to do a "strange" (but useful in my case) function that can return a dynamic list whose len depends on the amount of receiver.

For example:

f() returns a dynamic list of None, so I can do the following:

a = f()  => a = None
a, b = f()  => a=b= None
(a, b) = f() => a=b= None
(a, b, c, d, e, f) = f()  => a=b=c=d=e=f= None

I think this might be done via generator comprehension or iterator, but I was blocked on how to get the amount of recevier. Maybe I was in the wrong direction. Would you advise me some tips?

Any helps will be appreciated.

Many Thank,

Tiezhen


Solution

  • Unfortunately, Python unpacks returned tuples using the Pythonic "it's easier to ask forgiveness than permission" approach. That is, if you have a statement:

    a,b,c = f()
    

    Behind the scenes, it's doing something along the lines of:

    try:
        a = returned[0]
        b = returned[1]
        c = returned[2]
    except IndexError:
        raise ValueError('need more than k values to unpack')
    
    try:
        _ = returned[4]
    except IndexError:
        pass
    else:
        raise ValueError('too many values to unpack')
    

    So it's discovering dynamically the number of values returned. Unfortunately, that precludes us from being clever and creating a new type for handling variable returns:

    class VariableReturn(object):
        def __getitem__(self, index):
            return ...
    

    In Python 3, you can sort of do what you're asking, but the burden is on the caller, not the function being called. The function should always return the same number of results, but we'll trap the remaining results using extended tuple unpacking, as shown in this StackOverflow question.

    Using this approach, you can return as many results as you'd like, but you need to always return at least as many as you need in the maximal case. The rest get packed into a trailing tuple.

    a,*others = f()
    a,b,*others = f()
    a,b,c,*others = f()