[Python-ideas] Positional-only parameters

Matthias Bussonnier bussonniermatthias at gmail.com
Tue Feb 28 17:31:30 EST 2017


> I just noticed a module on PyPI to implement this behaviour on Python functions:

>   https://pypi.python.org/pypi/positional

This library seem to do the opposite of what you ask and force kwarg only.

In [11]: @positional.positional(1)
    ...: def foo(a=1,b=2):
    ...:     print(a,b)
    ...:

In [12]: foo(a=1,b=2) # should have raised.
1 2

In [13]: foo(1,b=2)
1 2

This seem to be the right thing:

https://pypi.python.org/pypi/positionalonly

In [1]: @positionalonly(1)
   ...: def foo(a=1,b=2):
   ...:     print(a,b)

In [2]: foo(1, 2)
1 2

In [3]: foo(a=1,b=2)
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-3-78db88131ebc> in <module>()
----> 1 foo(a=1,b=2)

/Users/bussonniermatthias/anaconda/lib/python3.5/site-packages/positionalonly/__init__.py
in fun(*args, **kwargs)
    208             ])
    209             raise TypeError("The following parameters of `{}`
are positional only.\n"
--> 210                             "They were used as keywords
arguments:\n{}".format(function.__qualname__, lst))
    211         if insertn and len(args) >= insertn:
    212             args = args[:insertn] + (None,) + args[insertn:]

TypeError: The following parameters of `foo` are positional only.
They were used as keywords arguments:
 - 'a' (1) should be in 0th position

-- 
M

On Tue, Feb 28, 2017 at 2:17 PM, M.-A. Lemburg <mal at egenix.com> wrote:
> On 28.02.2017 22:17, Victor Stinner wrote:
>> Hi,
>>
>> For technical reasons, many functions of the Python standard libraries
>> implemented in C have positional-only parameters.
>
> Keyword argument handling is comparatively slow and rarely
> needed for non-optional positional parameters of built-ins.
>
> You might make a case for optional ones, but then: how often are
> these used in practice to warrant the drop in performance ?
>
> Note: All this is different for Python methods/functions. The
> overhead of keyword parsing is small compared to what Python
> has to do to setup new frames for execution.
>
>> Example:
>> -------
>> $ ./python
>> Python 3.7.0a0 (default, Feb 25 2017, 04:30:32)
>>>>> help(str.replace)
>> replace(self, old, new, count=-1, /)   # <== notice "/" at the end
>>     ...
>>>>> "a".replace("x", "y")  # ok
>> 'a'
>>
>>>>> "a".replace(old="x", new="y")   # ERR!
>> TypeError: replace() takes at least 2 arguments (0 given)
>> -------
>>
>> When converting the methods of the builtin str type to the internal
>> "Argument Clinic" tool (tool to generate the function signature,
>> function docstring and the code to parse arguments in C), I asked if
>> we should add support for keyword arguments in str.replace(). The
>> answer was quick: no! It's a deliberate design choice.
>>
>> Quote of Yury Selivanov's message:
>> """
>> I think Guido explicitly stated that he doesn't like the idea to
>> always allow keyword arguments for all methods. I.e. `str.find('aaa')`
>> just reads better than `str.find(needle='aaa')`. Essentially, the idea
>> is that for most of the builtins that accept one or two arguments,
>> positional-only parameters are better.
>> """
>> http://bugs.python.org/issue29286#msg285578
>>
>> I just noticed a module on PyPI to implement this behaviour on Python functions:
>>
>>    https://pypi.python.org/pypi/positional
>>
>> My question is: would it make sense to implement this feature in
>> Python directly? If yes, what should be the syntax? Use "/" marker?
>> Use the @positional() decorator?
>>
>> Do you see concrete cases where it's a deliberate choice to deny
>> passing arguments as keywords?
>>
>> Don't you like writing int(x="123") instead of int("123")? :-) (I know
>> that Serhiy Storshake hates the name of the "x" parameter of the int
>> constructor ;-))
>
> ... and that's another reason why to avoid them: the naming
> of positional parameters was never really taken into account
> when writing the C functions and it does even change
> sometimes without warning.
>
>> By the way, I read that "/" marker is unknown by almost all Python
>> developers, and [...] syntax should be preferred, but
>> inspect.signature() doesn't support this syntax. Maybe we should fix
>> signature() and use [...] format instead?
>
> +1
>
>> Replace "replace(self, old, new, count=-1, /)" with "replace(self,
>> old, new[, count=-1])" (or maybe even not document the default
>> value?).
>>
>> Python 3.5 help (docstring) uses "S.replace(old, new[, count])".
>
> Using "count=-1" looks confusing when the method doesn't
> allow keyword arguments, so it's probably better to use the 3.5
> style and document the defaults in the doc-string.
>
> AFAIR, some of these don't even have a (documented) default value.
>
> --
> Marc-Andre Lemburg
> eGenix.com
>
> Professional Python Services directly from the Experts (#1, Feb 28 2017)
>>>> Python Projects, Coaching and Consulting ...  http://www.egenix.com/
>>>> Python Database Interfaces ...           http://products.egenix.com/
>>>> Plone/Zope Database Interfaces ...           http://zope.egenix.com/
> ________________________________________________________________________
>
> ::: We implement business ideas - efficiently in both time and costs :::
>
>    eGenix.com Software, Skills and Services GmbH  Pastor-Loeh-Str.48
>     D-40764 Langenfeld, Germany. CEO Dipl.-Math. Marc-Andre Lemburg
>            Registered at Amtsgericht Duesseldorf: HRB 46611
>                http://www.egenix.com/company/contact/
>                       http://www.malemburg.com/
>
> _______________________________________________
> Python-ideas mailing list
> Python-ideas at python.org
> https://mail.python.org/mailman/listinfo/python-ideas
> Code of Conduct: http://python.org/psf/codeofconduct/


More information about the Python-ideas mailing list