Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why use positional-only parameters in Python 3.8+?

A new "positional-only parameters" syntax has been introduced in 3.8.

From Positional-only parameters in the documentation:

There is new syntax (/) to indicate that some function parameters must be specified positionally (i.e., cannot be used as keyword arguments). This is the same notation as shown by help() for functions implemented in C (produced by Larry Hastings’ Argument Clinic tool).

Why ever use this syntax? Why is it better for the code's user?

It seems to me that this makes it harder for users to specify what their arguments actually mean, if they so desire. Why make it harder on the user?

like image 926
Gulzar Avatar asked Sep 12 '25 17:09

Gulzar


2 Answers

To briefly summarize the stated rationales in PEP 570, the PEP that added positional-only arguments:

  1. Many built-in functions implemented in C already did not accept keyword arguments, even before Python 3.8. Allowing positional-only argument allows python code to be consistent with C code
  2. Some python classes, such as the constructor for the dict type, take arbitrary keyword arguments. If you were to try to define a class with such behavior in python, you would have to write def __init__(self, **kwds), ... except then you can't have a keyword argument named self!. Positional-only arguments can avoid this flaw.
  3. Some functions don't have any natural name to assign their argument to. Take the int constructor. int(x="3") is no more readable than int("3"). Positional-only arguments allow names that have no inherent meaning to be considered implementation details rather than part of the public API of the module.

There are a few more details in the PEP, but those three points summarize the general reason for the existence of the feature.

like image 81
pppery Avatar answered Sep 15 '25 08:09

pppery


One reason is that people rename their function arguments and then all of the function calls which used keywords no longer work properly.

For example, given a function as follows:

def pow(base: float, exponent: int) -> float:
   pass

you could write function calls using positional or keyword arguments:

pow(4.5, 10)
pow(4.5, exponent=10)
pow(exponent=10, base=4.5)

If the arguments were subsequently renamed:

def pow(base: float, exp: int) -> float:
   """
        CHANGE LOG OR VERSION HISTORY:
           `exponent` renamed to `exp`
   """   
   pass 

then calls referring to the old argument names would give a TypeError:

pow(4.5, 10)  # OK
pow(4.5, exponent=10)  # TypeError
pow(exponent=10, base=4.5)  # TypeError

One potential rememdy is requiring consumers to use only positional arguments:

def pow(base: float, exponent: int, /) -> float:
    pass
like image 20
2 revs, 2 users 73%Samuel Muldoon Avatar answered Sep 15 '25 08:09

2 revs, 2 users 73%Samuel Muldoon