Question

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

Was it helpful?

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()

OTHER TIPS

This is not possible in Python. The function on the right hand site has no knowledge of the context it was called in. The right hand site is evaluated before any of the name bindings take place.

If you don't mind using Python 3, you can ignore what you don't need, for example:

a, b, c, d, *_ = (x for x in range(100))

Try this:

def f(n):
    return (None, ) * n

For example:

a, b, c = f(3)

... That's about as far as you can get, since in Python there's no way to know how many variables are in the left-hand side of an assignment.

Can't be done.

Functions in Python return one value, only. While it may sometimes look like more, it's still just one value: a tuple. Multiple assignment is then a process of tuple unpacking.

Your question then can be restated: can we create an object that acts like a tuple of varying length, depending on how many values need to be unpacked? And that's simply not made available as an option.

Probably the closest I can think of is to use a generator and get the desired number of items with itertools.islice:

a = itertools.count()
x, y, z = itertools.islice(a, 3) # 0, 1, 2
u, v = itertools.islice(a, 2)    # 3, 4

But that's pretty far from what was hoped for.

pretty not nice but perhaps this helps you:

def f(x):
    for i in x:
        globals()[i] = None

f(['a','b','c'])
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top