[Python-ideas] values in vs. values out

Jason Orendorff jason.orendorff at gmail.com
Thu Jan 13 21:11:00 CET 2011

On Thu, Jan 13, 2011 at 9:21 AM, Luc Goossens <luc.goossens at cern.ch> wrote:
> Sorry maybe this was not clear from my mail but I am not so much interested
> in possible work-arounds but in why this asymmetry exists in the first
> place.
> I mean is there a reason as to why it is the way it is, or is it just that
> nobody ever asked for anything else.

There are two kinds of asymmetry here. One is semantic and one is syntactic.

1. Semantically, function calls are fundamentally asymmetric in
Python. A call takes as its input a tuple of arguments and a
dictionary of keyword arguments, but its output is either a single
return value or a single raised exception.

2. Syntactically, the syntax for composing a value (tuple expressions,
list/set/dict displays, constructor calls) differs from the syntax for
decomposing a value into its parts (unpacking assignment).

The ML family of programming languages eliminate both asymmetries
about as completely as I can imagine. ML functions take one argument
and return one value; either can be a tuple. The same pattern-matching
syntax is used to cope with parameters and return values. To a very
great degree the syntax for composing a tuple, record, or list is the
same as the syntax for decomposing it. So what you're asking is at
least demonstrably possible, at least for other languages.

So why does Python have these asymmetries?

1. The semantic asymmetry (functions taking multiple parameters but
returning a single value) is a subtle thing. Even in Scheme, where
conceptual purity and treating continuations as procedures are core
design principles of the entire language, this asymmetry is baked into
(lambda) and the behavior of function calls. And even in ML there is
*some* asymmetry; a function can die with an error rather than return
anything. (You can "error out" but not "error in".)

In Python's design, I imagine Guido found this particular asymmetry
made the language fit the brain better. It's more like C. The greater
symmetry in languages like ML may have felt like be too much--and one
more unfamiliar thing for new users to trip over.

In any case it would be impractical to change this in Python. It's
baked into the language, the implementation, and the C API.

2. The syntactic asymmetry is made up of lots of little asymmetries,
and I think it's enlightening to take a few of them case by case.

 (a) You can write
        [a, b] = [1, 2]
      but not
        {a, b} = {1, 2}
        {"A": a, "B": b} = {"A": 1, "B": 2}
      Sets have no deterministic order, so the second possibility is
      misleading. The third is not implemented, I imagine, purely
      for usability reasons: it would do more harm than good.

 (b) You can write
        x = complex(1, 2)
      but not
        complex(a, b) = x
      In ML-like languages, you can identify constructors at compile
      time, so it's clear on the left-hand side of something like this
      what variables are being defined. In Python it's not so
      obvious what this is supposed to do.

 (c) Unlike ML, you can write
        (a, b) = [1, 2]
      or generally
        a, b = any_iterable
      It is useful for unpacking to depend on the iterable protocol
      rather than the exact type of the right-hand side. This is a
      nicety that ML-like languages don't bother with, afaik.

  (d) You can write
        def f(x, y, a) : ...
      but not
        (x, y, a) = **dct
      and conversely you can write
        lst[1] = x
      but not
        def f(lst[1]): ...
      In both cases, I find the accepted syntax sane, and the
      symmetric-but-currently-not-accepted syntax baffling.
      Note that in the case of lst[1] = x, we are mutating an
      existing object, something ML does not bother to make

All four of these cases seem to boil down to what's useful vs. what's
confusing. You could go on for some time in that vein.

Hope this helps.


More information about the Python-ideas mailing list