[Python-3000] PEP 3102

Joel Bender jjb5 at cornell.edu
Fri Feb 15 17:46:28 CET 2008


Dj Gilcrease wrote:
> On Thu, Feb 14, 2008 at 6:04 PM, Greg Ewing <greg.ewing at canterbury.ac.nz> wrote:
>> Guido van Rossum wrote:
>>  > Now can you come up with a syntax for positional-only
>>  > arguments? So far everybody has failed at that, and there are some use
>>  > cases where it's useful too.
> 
> 
> throwing some ideas around...

How about a BNFish notation?  Use brackets around optional parameters.

     def test([arg1, [arg2,]] arg3):
         ...

I haven't found an example of what the value of an unspecified 
positional only argument would be, I think it should be required:

     def test([arg1=1,] arg2): return (arg1, arg2)

This could also accommodate trailing positional only args, even though 
the existing syntax already has it (but keep reading):

     def test(arg1 [, arg2=2]): return (arg1, arg2)
     assert test(1) == (1, 2)
     assert test(1,3) == (1, 3)

If both were provided:

     def test([arg1=1,] arg2 [, arg3=3]): ... # error

I would expect it to be an "ambiguous combination of optional 
positional-only arguments" syntax error (as opposed to runtime error).

If you wanted arg2 specified when arg1 is:

     def test([arg1=1, arg2=2,] arg3): return (arg1, arg2, arg3)
     assert test(9) == (1, 2, 9)
     assert test(7, 8, 9) == (7, 8, 9)

     test(8, 9)                   # error

With nesting you can specify which one is more optional:

     def test([[arg1=1,] arg2=2,] arg3): return (arg1, arg2, arg3)
     assert test(9) == (1, 2, 9)
     assert test(8, 9) == (1, 8, 9)

     def test([arg1=1, [arg2=2,]] arg3): return (arg1, arg2, arg3)
     assert test(8, 9) == (8, 2, 9)

Capturing all of the args except the last one:

     def test([*arg1,] arg2): return (arg1, arg2)
     assert test(9) == ((), 9)
     assert test(8, 9) == ((8,), 9)
     assert test(7, 8, 9) == ((7, 8), 9)

First is a little more important:

     def test([arg1=1, *arg2,] arg3): return (arg1, arg2, arg3)
     assert test(9) == (1, (), 9)
     assert test(8, 9) == (8, (), 9)
     assert test(7, 8, 9) == (7, (8,), 9)

Force the end of positional arguments to switch to keywords:

     def test([*arg1,] arg2, *, arg3=3): return (arg1, arg2, arg3)

Specifying more than one dumping spot for additional positional 
parameters is ambiguous:

     def test([arg1=1, *arg2,] arg3, *arg4): ... # error

Specifying default values for a positional argument may make it ambiguous:

     def test([arg1=1,] arg2, arg3=3): return (arg1, arg2, arg3)

This is OK, but not recommended, it's more complicated than it needs to be:

     def test(arg1 [, arg2=1 [, arg3=2]]): return (arg1, arg2, arg3)

And now for something completely different:

     def test(arg1 [[, arg2=2], arg3=3]): return (arg1, arg2, arg3)
     assert test(8) == (8, 2, 3)
     assert test(8, 9) == (8, 2, 9)
     assert test(7, 8, 9) == (7, 8, 9)

Like the other dumping spot:

     def test(arg1 [[, *arg2], arg3=3]): return (arg1, arg2, arg3)
     assert test(8) == (8, (), 3)
     assert test(8, 9) == (8, (), 9)
     assert test(7, 8, 9) == (7, (8,), 9)

Nested galore:

     def test([arg1=1, [[*arg2,] arg3=3,]] arg4):
         return (arg1, arg2, arg3, arg4)
     assert test(7) = (1, (), 3, 7)
     assert test(7, 8) = (7, (), 3, 8)
     assert test(7, 8, 9) = (7, (), 8, 9)
     assert test(7, 8, 9, 10) = (7, (8,), 9, 10)

The notation for an optional tuple that gets ripped apart seems busy, 
but is still grokable:

     def test([(arg1, arg2)=(1, 2),] arg3): return (arg1, arg2, arg3)
     assert test(8) == (1, 2, 8)
     assert test((7, 8), 9) == (7, 8, 9)


Joel


More information about the Python-3000 mailing list