Re: [Python-ideas] Positional only arguments

On 5/16/07, Benji York <benji@zope.com> wrote:
What's the future of "private" attributes in Py3K ? I remember Raymond Hettinger bringing up a challenge on c.l.py about a decorator that could replace the double underscore mangling and Michele Simionato caming up with a bytecode hack that showed it is possible. If they're staying though, +epsilon for blessing __args as positional-only (for some positive epsilon ;-)). George -- "If I have been able to see further, it was only because I stood on the shoulders of million monkeys."

On 5/16/07, George Sakkis <george.sakkis@gmail.com> wrote:
Nobody submitted a PEP to remove them in time for any of the several deadlines I gave, so they are staying. (I think that even if a PEP had been submitted it would probably have been rejected, after a long discussion.) But I'd love to see better syntax for positional-only arguments. What I would like to be able to do is somehow write a signature like this: def foo(abc, xyz=42): ... where both arguments (if present) *must* be given using positional notation, so that foo(42) and foo(42, 24) are legal, but foo(abc=42) and foo(42, xyz=24) are illegal. (Alas, I don't have any clever suggestions.) This could be proposed as an addition for 2.6 and then we'd have to slip it into 3.0. -- --Guido van Rossum (home page: http://www.python.org/~guido/)

On 5/16/07, Guido van Rossum <guido@python.org> wrote:
I'd particularly like to see some way to do this because it would make duplicating the dict() and dict.update() signatures easier. Currently you could write:: class C(object): def __init__(self, obj=None, **kwargs): but this breaks when you try something like:: C(obj='foo', bar='baz') and expect both keyword arguments to be caught in the **kwargs. And let's hope you never need to write something like:: C(self=1, other=2) where you'll get a:: TypeError: __init__() got multiple values for keyword argument 'self' The current correct version looks like:: class C(object): def __init__(*args, **kwargs): self = args[0] if len(args) == 2: obj = args[1] elif len(args) == 1: obj = None else: raise TypeError() Nasty. STeVe -- I'm not *in*-sane. Indeed, I am so far *out* of sane that you appear a tiny blip on the distant coast of sanity. --- Bucky Katt, Get Fuzzy

On Wed, May 16, 2007 5:45 pm, Guido van Rossum wrote: [...]
One could decorate foo with: def posonly(f): def posf(*args, **kwargs): return f(*args, *kwargs) posf.__name__ = f.__name__ return f So: @posonly def foo(abc, xyz=42):... would behave as you want. Of course it doesn't have an interesting signature. By extension one could have the arglist element *(a, b, c) for positional-only arguments and **(x, y, z) for keyword-only arguments: def foo(*(abc, xyz=42)):... def bar(a, b, **(x, y=2)):... # a and b are positional/keyword arguments # x is keyword-only and mandatory # y is keyword-only with a default value of 2 It sort of fits with the current use of * as when calling foo: foo(my_abc, my_xyz) is equivalent to foo(*(my_abc, my_xyz)) -- Arnaud

This decorator solution is the best I've seen so far! It is probably possible to (a) copy signature info into the returned wrapper, and (b) support keyword args (after the lone '*' or after *args). --Guido On 5/17/07, Arnaud Delobelle <arno@marooned.org.uk> wrote:
-- --Guido van Rossum (home page: http://www.python.org/~guido/)

Has anyone considered the Common Lisp argument list as a place to look for ideas? (var... &optional (var initform svar)... &rest var &key ((keyword var) initform svar)... &aux (var initform)...) http://www.cs.cmu.edu/Groups/AI/html/cltl/clm/node64.html Rick

On Fri, May 18, 2007 7:35 am, Arnaud Delobelle wrote: [...]
I wrote this just before going to work this morning, and of course I didn't try it or probably even reread it... So apart from the typos it doesn't work with **kwargs. I've got a working version: def posonly(arg): def deco(f, nposargs): name = f.__name__ posargnames = f.func_code.co_varnames[:nposargs] def posf(*args, **kwargs): for kw in kwargs: if kw in posargnames: raise TypeError("%s() arg '%s' is posonly" % (name, kw)) return f(*args, **kwargs) posf.__name__ = name return posf if isinstance(arg, int): return lambda f: deco(f, arg) else: return deco(arg, arg.func_code.co_argcount) It works like this: @posonly def foo(x, y, z=10, t=100): # All arguments are positional only # foo(1, 2, 3) -> 106 # foo(1, y=2) -> TypeError # foo(1, t=7) -> TypeError return x+y+z+t @posonly(2) def bar(x, y=1, z=10, t=100): # Only the first two arguments are posonly # bar(1, y=2) -> TypeError # bar(1, z=0) -> 102 Being a mere python end-user, I don't know if I'm using the func_code attribute of functions correctly, so this might break in various ways! -- Arnaud

On 5/16/07, George Sakkis <george.sakkis@gmail.com> wrote:
Nobody submitted a PEP to remove them in time for any of the several deadlines I gave, so they are staying. (I think that even if a PEP had been submitted it would probably have been rejected, after a long discussion.) But I'd love to see better syntax for positional-only arguments. What I would like to be able to do is somehow write a signature like this: def foo(abc, xyz=42): ... where both arguments (if present) *must* be given using positional notation, so that foo(42) and foo(42, 24) are legal, but foo(abc=42) and foo(42, xyz=24) are illegal. (Alas, I don't have any clever suggestions.) This could be proposed as an addition for 2.6 and then we'd have to slip it into 3.0. -- --Guido van Rossum (home page: http://www.python.org/~guido/)

On 5/16/07, Guido van Rossum <guido@python.org> wrote:
I'd particularly like to see some way to do this because it would make duplicating the dict() and dict.update() signatures easier. Currently you could write:: class C(object): def __init__(self, obj=None, **kwargs): but this breaks when you try something like:: C(obj='foo', bar='baz') and expect both keyword arguments to be caught in the **kwargs. And let's hope you never need to write something like:: C(self=1, other=2) where you'll get a:: TypeError: __init__() got multiple values for keyword argument 'self' The current correct version looks like:: class C(object): def __init__(*args, **kwargs): self = args[0] if len(args) == 2: obj = args[1] elif len(args) == 1: obj = None else: raise TypeError() Nasty. STeVe -- I'm not *in*-sane. Indeed, I am so far *out* of sane that you appear a tiny blip on the distant coast of sanity. --- Bucky Katt, Get Fuzzy

On Wed, May 16, 2007 5:45 pm, Guido van Rossum wrote: [...]
One could decorate foo with: def posonly(f): def posf(*args, **kwargs): return f(*args, *kwargs) posf.__name__ = f.__name__ return f So: @posonly def foo(abc, xyz=42):... would behave as you want. Of course it doesn't have an interesting signature. By extension one could have the arglist element *(a, b, c) for positional-only arguments and **(x, y, z) for keyword-only arguments: def foo(*(abc, xyz=42)):... def bar(a, b, **(x, y=2)):... # a and b are positional/keyword arguments # x is keyword-only and mandatory # y is keyword-only with a default value of 2 It sort of fits with the current use of * as when calling foo: foo(my_abc, my_xyz) is equivalent to foo(*(my_abc, my_xyz)) -- Arnaud

This decorator solution is the best I've seen so far! It is probably possible to (a) copy signature info into the returned wrapper, and (b) support keyword args (after the lone '*' or after *args). --Guido On 5/17/07, Arnaud Delobelle <arno@marooned.org.uk> wrote:
-- --Guido van Rossum (home page: http://www.python.org/~guido/)

Has anyone considered the Common Lisp argument list as a place to look for ideas? (var... &optional (var initform svar)... &rest var &key ((keyword var) initform svar)... &aux (var initform)...) http://www.cs.cmu.edu/Groups/AI/html/cltl/clm/node64.html Rick

On Fri, May 18, 2007 7:35 am, Arnaud Delobelle wrote: [...]
I wrote this just before going to work this morning, and of course I didn't try it or probably even reread it... So apart from the typos it doesn't work with **kwargs. I've got a working version: def posonly(arg): def deco(f, nposargs): name = f.__name__ posargnames = f.func_code.co_varnames[:nposargs] def posf(*args, **kwargs): for kw in kwargs: if kw in posargnames: raise TypeError("%s() arg '%s' is posonly" % (name, kw)) return f(*args, **kwargs) posf.__name__ = name return posf if isinstance(arg, int): return lambda f: deco(f, arg) else: return deco(arg, arg.func_code.co_argcount) It works like this: @posonly def foo(x, y, z=10, t=100): # All arguments are positional only # foo(1, 2, 3) -> 106 # foo(1, y=2) -> TypeError # foo(1, t=7) -> TypeError return x+y+z+t @posonly(2) def bar(x, y=1, z=10, t=100): # Only the first two arguments are posonly # bar(1, y=2) -> TypeError # bar(1, z=0) -> 102 Being a mere python end-user, I don't know if I'm using the func_code attribute of functions correctly, so this might break in various ways! -- Arnaud
participants (5)
-
Arnaud Delobelle
-
George Sakkis
-
Guido van Rossum
-
Rick Martin
-
Steven Bethard