I think I "get" what Thomas is talking about here:

Starting with the simplest example, when defining a function, you can have one take a single positional parameter:

def fun(x):

and you can have code all over the place that calls it:


Later on, if you want to exapand the API, ytou can add a keyword parameter:

def fun(x, y=None):

And all the old code that already calls that function with one argument still works, and newer code can optionally specify the keyword argument -- this is a really nice feature that makes Python very refactorable. 

But for return values, there is no such flexibility -- if you have already written your function with the simple API:

def fun(...):
    return something

And it is being used already as such:

x = fun()

Then you decide that an optional extra return value would be useful, and you re-write your function:

def fun(...):
    return something, something_optional

now all the call locations will need to be updated:

x, y = fun()

or maybe:

x, __ = fun()

Sure, if you had had the foresight, then you _could_ have written your original function to return a more flexible data structure (dict, NamedTuple, etc), but, well, we usually don't have that foresight :-).

My first thought was that function return tuples, so you could document that your function should be called as such:

x = fun()[0]

but, alas, tuple unpacking is apparently automatically disabled for single value tuples  (how do you distinguish a tuple with a single value and the value itself??) . so you could do this if you started with two or more return values:

x, y = fun()[:2]

OR you could hae your original function return a len-1 tuple in the first place:

def test():
     return (5,)

but then that would require the same foresight.

So: IIUC, Thomas's idea is that there be some way to have"optional" return values, stabbing at a possible syntax to make the case:


def fun():
    return 5

called as:

x = fun()


def fun()
    return 5, *, 6

Now it can still be called as:

x = fun()

and result in x == 5


x, y = fun()

and result in x == 5, y == 6

So: syntax asside, I'm not sure how this could be implemented -- As I understand it, functions return either a single value, or a tuple of values -- there is nothing special about how assignment is happening when a function is called. That is:

result = fun()
x = result

is exactly the same as:

x = fun()

So to impliment this idea, functions would have to return an object that would act like a single object when assigned to a single name:

x = fun()

but an unpackable object when assigned to multiple names:

x, y = fun()

but then, if you had this function:

def fun()
    return x, *, y

and you called it like so:

result = fun()
x, y = result

either x, y = result would fail, or result would be this "function return object", rather than the single value.

I can't think of any way to resolve that problem without really breaking the language.


On Sat, Jan 26, 2019 at 9:48 AM Steven D'Aprano <steve@pearwood.info> wrote:
On Sat, Jan 26, 2019 at 12:01:55PM -0500, Wes Turner wrote:

> Tuples are a dangerous (and classic, legacy) interface contract.


Python-ideas mailing list
Code of Conduct: http://python.org/psf/codeofconduct/

Christopher Barker, PhD

Python Language Consulting
  - Teaching
  - Scientific Software Development
  - Desktop GUI and Web Development
  - wxPython, numpy, scipy, Cython