# PEP 570: Python Positional-Only Parameters

**URL:** <https://discuss.python.org/t/pep-570-python-positional-only-parameters/1078>\
**Category:** PEPs\
**Created:** [March 28, 2019, 12:04am UTC](https://discuss.python.org/t/pep-570-python-positional-only-parameters/1078 "2019-03-28T00:04:34Z")\
**Posts on this page:** 20\
**Page:** 6

<div class="post-metadata">

**Author:** ![storchaka](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/storchaka/32/217_2.png) [@storchaka](https://discuss.python.org/u/storchaka)\
**Post date:** [March 31, 2019, 7:33am UTC](https://discuss.python.org/t/pep-570-python-positional-only-parameters/1078/101 "2019-03-31T07:33:48Z")

</div>

> Many of these changes are breaking, since people may be passing the existing arguments by name.

You are right. We should add deprecation warnings similarly as in the UserDict constructor.

---

<div class="post-metadata">

**Author:** ![pf\_moore](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/pf_moore/32/35_2.png) [@pf\_moore](https://discuss.python.org/u/pf_moore)\
**Post date:** [March 31, 2019, 10:50am UTC](https://discuss.python.org/t/pep-570-python-positional-only-parameters/1078/102 "2019-03-31T10:50:01Z")

</div>

> [@njs](#):
>
> I’m just saying, consider two ways of writing [these docs](https://docs.python.org/3/library/functions.html#float):
> 
> > _@positional\_only\_args_  
> > _class_ **`float`** (x=0.0)  
> > Return a floating point number constructed from a number or string _x_ .
> 
> > _class_ **`float`** (x=0.0, /)  
> > Return a floating point number constructed from a number or string _x_ .
> 
> Some people will dislike both, and some people will be happy with both, but it’s hard for me to imagine anyone saying that they think the second one is clear and obvious, but the first one is opaque and confusing :-).

Some people (e.g. me!) will think the first one is clear and obvious and the second is opaque and confusing 😄

I could live with the `/` notation, but it is as ugly as sin. I’d likely learn to live with it, and as @guido pointed out, no-one has come up with a less ugly solution - but I think that’s only true if you restrict yourself to syntax based options (and more specifically, options that are appropriate in the context of Argument Clinic, because that’s where the `/` notation was introduced, _not_ as Python syntax although my recollection is that it was intended as Python-compatible).

IMO, the decorator syntax is attractive enough (although so far only in isolated examples intended to “sell” the idea 😉) to be worth at least exploring further.

---

<div class="post-metadata">

**Author:** ![storchaka](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/storchaka/32/217_2.png) [@storchaka](https://discuss.python.org/u/storchaka)\
**Post date:** [March 31, 2019, 4:10pm UTC](https://discuss.python.org/t/pep-570-python-positional-only-parameters/1078/103 "2019-03-31T16:10:58Z")

</div>

Is there a sample implementation of PEP 570? I afraid that the implementation of the decorator idea will be more complex.

---

<div class="post-metadata">

**Author:** ![gpshead](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/gpshead/32/54_2.png) [@gpshead](https://discuss.python.org/u/gpshead)\
**Post date:** [March 31, 2019, 6:22pm UTC](https://discuss.python.org/t/pep-570-python-positional-only-parameters/1078/104 "2019-03-31T18:22:59Z")

</div>

> [@njs](#):
>
> where a bunch of well-known Python experts said they had no idea what the `/` notation meant

This didn’t strike me as odd at all. It wasn’t Python language syntax. It only appeared in help text due primarily to CPython internals-only argument clinic adoption. There has really been no good reason for most people to care about it. It was much easier to just willfully overlook the / as being a weird glitch in documentation rendering and move on with practical work.

If we adopt this PEP with /, people will learn what it is.

---

<div class="post-metadata">

**Author:** ![gpshead](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/gpshead/32/54_2.png) [@gpshead](https://discuss.python.org/u/gpshead)\
**Post date:** [March 31, 2019, 7:01pm UTC](https://discuss.python.org/t/pep-570-python-positional-only-parameters/1078/105 "2019-03-31T19:01:16Z")

</div>

> [@guido](#):
>
> Is everyone aware that the `/` is meant to be the opposite of `*`? This is meant as a mnemonic. “Everything after `*` is keyword only, everything before `/` is positional only, everything in between can be used either way.”

_(quote above edited to use markdown – the asterisks were disappearing)._

I’m understand that. I just don’t _love_ the `/`. Regardless of token, the unique delineation between all three potential arglist sections makes perfect sense.

A `*` has had meaning within Python arguments forever both in single and double form, so adopting it stand alone for keyword only syntax was very natural. `/` has never been used in any context other than division in Python, seeing it gain an additional meaning slightly raises some eyebrows. But so would using any of the other single character punctuation tokens `:;.@^%|&+-~`.

Maybe “`;`” instead of “`, /,`” would be neat for this purpose as it would read nicely. Yet another alternative proposal I’ll pre-emptively reject:

```python
def sink_swamp_castle(burn; *, who_doesnt_leave="He"): ...
def meet_wizard(name;): ...

```

That use of semicolon in place of the comma seems somewhat englishy but I suspect would ultimately lead to more confusion than a `/` in the list.

> [@guido](#):
>
> there is no less ugly syntax, at least nothing that doesn’t feel just as arbitrary.

Agreed.

---

<div class="post-metadata">

**Author:** ![gpshead](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/gpshead/32/54_2.png) [@gpshead](https://discuss.python.org/u/gpshead)\
**Post date:** [March 31, 2019, 7:31pm UTC](https://discuss.python.org/t/pep-570-python-positional-only-parameters/1078/106 "2019-03-31T19:31:00Z")

</div>

> [@pablogsal](#):
>
> It has been suggested on python-ideas[^20](https://mail.python.org/pipermail/python-ideas/2017-February/044888.html) to provide a decorator  
> written in Python as an implementation for this feature.

An additional reference to add - A pure python decorator from 2007 exists:

[https://code.activestate.com/recipes/521874-functions-with-positional-only-arguments/](https://code.activestate.com/recipes/521874-functions-with-positional-only-arguments/)

If we were to seriously consider a decorator implementation we’d need to do it such that it was a special one ala `@classmethod` that has no startup time or runtime cost and leaves no room for error on specifying what exactly was positional. I’m -1 on decorators for this which appear already rejected so I won’t dive in on that (others are already doing so).

---

<div class="post-metadata">

**Author:** ![pganssle](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/pganssle/32/245_2.png) [@pganssle](https://discuss.python.org/u/pganssle)\
**Post date:** [March 31, 2019, 9:05pm UTC](https://discuss.python.org/t/pep-570-python-positional-only-parameters/1078/107 "2019-03-31T21:05:03Z")

</div>

> [@gpshead](#):
>
> We should avoid shaming developers for using features we add.

I’m sorry if my suggestion came off this way, I certainly didn’t want to suggest that it would be somehow shameful to use this functionality. As a library maintainer concerned about API evolution, I’m already in the target audience for this, so I definitely don’t think people should be shamed for using it.

I was hoping there might be a more neutral compromise wording that would satisfy people (like me) who think this is very useful and good functionality, and people who would be willing to see it added to improve the user experience for people who need this but are not willing to go so far as to promote its use. With additional thought, I’m not sure that there _is_ a good wording that wouldn’t be interpreted as shaming the user for using this functionality, though, so unless someone has a specific request to add some compromise wording to the PEP, I will drop this line of argument.

---

<div class="post-metadata">

**Author:** ![larry](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/larry/32/936_2.png) [@larry](https://discuss.python.org/u/larry)\
**Post date:** [March 31, 2019, 10:46pm UTC](https://discuss.python.org/t/pep-570-python-positional-only-parameters/1078/108 "2019-03-31T22:46:42Z")

</div>

> [@steve.dower](#):
>
> which docs should users have to read in order to use an API? Currently the signature is not sufficient because of \*args hacks.

`*args` is the exception, not the rule. And I suspect there are many cases where one can correctly intuit what `*args` is used for, e.g. `max()`. Anyway your point only (slightly) helps the case for the PEP: giving users more expressive power to design their APIs makes it easier for them to express themselves, and thus less likely to use `*args` hacks. Though I suppose it’s debatable about how much additional expressive power positional-only parameters affords the user.

---

<div class="post-metadata">

**Author:** ![larry](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/larry/32/936_2.png) [@larry](https://discuss.python.org/u/larry)\
**Post date:** [March 31, 2019, 11:00pm UTC](https://discuss.python.org/t/pep-570-python-positional-only-parameters/1078/109 "2019-03-31T23:00:58Z")

</div>

For what it’s worth, I just re-read PEP 457, my PEP proposing a positional-only parameters syntax. Six years on I find it a little bizarre. Yes, it revived Guido’s 2012 idea for `/` as the positional-only parameter delimiter. But I also blithely launch into “optional groups”, a concept I needed in Argument Clinic to express some funny functions that count their positional arguments and require some arguments in groups, e.g. `curses.subpad()` which either takes two or four arguments.

Let me say this about that: simply adding `/` to delimit positional-only parameters is not sufficient to express all Python library functions without `*args` and `len()` hacks. To cover everything you really do need something like “option groups” where one can have multiple parameters that must be specified or omitted as a unit. Supporting positional-only parameters in Python would let us express the semantics of some Python library functions more elegantly in pure Python, e.g. the `dict` constructor. But it falls short of getting us all the semantics to implement crazy things like `curses.window.overlay()`, which accepts either one or seven (!) arguments.

---

<div class="post-metadata">

**Author:** ![njs](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/njs/32/204_2.png) [@njs](https://discuss.python.org/u/njs)\
**Post date:** [April 1, 2019, 2:48am UTC](https://discuss.python.org/t/pep-570-python-positional-only-parameters/1078/110 "2019-04-01T02:48:15Z")

</div>

> [@gpshead](#):
>
> This didn’t strike me as odd at all. It wasn’t Python language syntax. It only appeared in help text due primarily to CPython internals-only argument clinic adoption. There has really been no good reason for most people to care about it. It was much easier to just willfully overlook the / as being a weird glitch in documentation rendering and move on with practical work.
> 
> If we adopt this PEP with /, people will learn what it is.

There’s a tendency in OSS discussions for things to turn really combative with everyone staking out positions early and punching back and forth, or assuming that other people are doing this and interpreting every comment as an all-out attack. I think it’s an unpleasant way to do things that promotes burnout and bad decisions, and try to avoid it 🙂 So please don’t assume that because I mentioned something about how people respond to `/` that it means I’m arguing that `/` is terrible and trying to destroy it… my priority is to understand what the trade-offs actually are between the different options.

In this case, I was specifically replying to @pablogsal’s claim that using `/` in docs would be more understandable to people than using decorators in docs, which seems extremely unlikely to me 🙂 I’m just saying, one of the trade-offs with `/` is that it’s pretty opaque the first time you see it – as you put it, it looks like a “weird glitch”. That’s not necessarily a bad thing; there are plenty of situations where everyone agrees that using terse punctuation is the best approach (e.g. infix arithmetic). But I hope we can at least agree that this is a trade-off!

This is part of why I think a crucial issue is how widespread the usage will be.

Arbitrary punctuation is especially great for common features, and especially bad for rare features. For example, it’s pretty arbitrary that Python uses `{}` for dicts and `[]` for lists, instead of the other way around. In an alternate world, we could have avoided this by requiring that everyone write out `dict(...)` and `list(...)` every time. But that would suck, b/c everyone uses dicts and lists constantly. So the arbitrary punctuation doesn’t hurt too much:

- yeah, you have to memorize it, but since you use it constantly, it’s like a little flash card in every line of code, so the memorization is easy
- memorizing is a one-time cost, and since the feature is commonly used, this cost is amortized over lots of usage
- in the mean time, the benefit of terseness gets multiplied by all these uses

But for rarer, more niche features, the calculation is totally different:

- you rarely see it, so learning/remembering it is harder
- the cost of memorizing doesn’t get amortized much, both because the feature is rare, and because you have to keep reminding yourself what it means
- And if you rarely use it, then who cares how terse it is?

---

<div class="post-metadata">

**Author:** ![toonarmycaptain](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/toonarmycaptain/32/183_2.png) [@toonarmycaptain](https://discuss.python.org/u/toonarmycaptain)\
**Post date:** [April 1, 2019, 3:05am UTC](https://discuss.python.org/t/pep-570-python-positional-only-parameters/1078/111 "2019-04-01T03:05:17Z")

</div>

Absolutely love this! I’m relatively new to coding, but just this week I was designing a method for which I’d like to do this!

---

<div class="post-metadata">

**Author:** ![pf\_moore](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/pf_moore/32/35_2.png) [@pf\_moore](https://discuss.python.org/u/pf_moore)\
**Post date:** [April 1, 2019, 7:47am UTC](https://discuss.python.org/t/pep-570-python-positional-only-parameters/1078/112 "2019-04-01T07:47:00Z")

</div>

Hi @toonarmycaptain, and welcome!

As someone relatively new to coding, maybe you could explain why you feel that positional-only parameters would be particularly important to your use case? One of the debates here is over the possibility that the feature will be over-used (it’s generally considered to be a relatively niche need) and it would help a lot to understand what motivates the use of the feature.

In all the years I’ve used Python, I’ve never really noticed the lack of positional-only parameters. My instinct says that it’s more likely to be something that people familiar with languages that don’t have named arguments want, but your comment makes me wonder if that intuition is wrong.

---

<div class="post-metadata">

**Author:** ![steve.dower](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/steve.dower/32/56_2.png) [@steve.dower](https://discuss.python.org/u/steve.dower)\
**Post date:** [April 1, 2019, 1:12pm UTC](https://discuss.python.org/t/pep-570-python-positional-only-parameters/1078/113 "2019-04-01T13:12:57Z")

</div>

> [@storchaka](#):
>
> Is there a sample implementation of PEP 570? I afraid that the implementation of the decorator idea will be more complex.

I’d implement the decorator to just add the number of positional only arguments as an attribute of the callable (rather than being a wrapper). Which is exactly what the `/` would result in, but without the grammar/parser changes. (Maybe someone could come up with a clever backport that implements one of the “tricks” automatically, but we don’t have to use that if we’re just going to make this a feature of the calling convention.)

---

<div class="post-metadata">

**Author:** ![storchaka](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/storchaka/32/217_2.png) [@storchaka](https://discuss.python.org/u/storchaka)\
**Post date:** [April 1, 2019, 1:45pm UTC](https://discuss.python.org/t/pep-570-python-positional-only-parameters/1078/114 "2019-04-01T13:45:10Z")

</div>

So the following code works?

```auto
@positional_only_args(1)
def foo(fmt, **kwargs):
    return fmt.format_map(kwargs)
assert foo('x={fmt}', fmt=42) == 'x=42'

```

---

<div class="post-metadata">

**Author:** ![steve.dower](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/steve.dower/32/56_2.png) [@steve.dower](https://discuss.python.org/u/steve.dower)\
**Post date:** [April 1, 2019, 1:47pm UTC](https://discuss.python.org/t/pep-570-python-positional-only-parameters/1078/115 "2019-04-01T13:47:52Z")

</div>

> [@larry](#):
>
> Anyway your point only (slightly) helps the case for the PEP: giving users more expressive power to design their APIs makes it easier for them to express themselves, and thus less likely to use `*args` hacks.

Yeah, that’s kinda where I was heading at that point in my thought process. Though I think I was thinking more about “well they’ll have to read the docs anyway so why not put a not-quite-honest signature there and explain the semantics in text”. Which we already do in the actual documentation in places, and I’ve certainly done it in docstrings.

But maybe some people feel like they need permission to have information like this “below the fold”, as it were?

---

<div class="post-metadata">

**Author:** ![steve.dower](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/steve.dower/32/56_2.png) [@steve.dower](https://discuss.python.org/u/steve.dower)\
**Post date:** [April 1, 2019, 1:50pm UTC](https://discuss.python.org/t/pep-570-python-positional-only-parameters/1078/116 "2019-04-01T13:50:30Z")

</div>

> [@storchaka](#):
>
> So the following code works?

In the same hypothetical world as the `/` variant working, sure.

Though it may be more expressive with a decorator to pass the names of arguments that “if passed by name, will always go into kwargs and never into a concrete parameter”?

---

<div class="post-metadata">

**Author:** ![toonarmycaptain](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/toonarmycaptain/32/183_2.png) [@toonarmycaptain](https://discuss.python.org/u/toonarmycaptain)\
**Post date:** [April 1, 2019, 1:53pm UTC](https://discuss.python.org/t/pep-570-python-positional-only-parameters/1078/117 "2019-04-01T13:53:58Z")

</div>

FIrstly, it’s plausible I’m doing something unwise. I have two classes, let’s call them `Class` and `Student`. You can add students to a class by using a method `Class.add_student()`. `Student` currently takes two arguments - `name` and `picture_path`, but will later take more. I want to design `Class's add_student()` method to not require changes every time `Student` has features added, eg arguments for position, weight, height arguments etc.

My first solution was to

```
def add_student(self, name: Union[str, Student], picture_path: Union[Path, str] = None):
        if isinstance(name, Student):
            self.students.append(name)
        else:
           self.students.append(Student(name, picture_path))

```

Which works fine, but I don’t feel it particularly helpful to have `name` be either a `Student` object or the student’s name, and this implementation is fragile to changes in `Student`'s signature (is that the term?), which will happen as I continue developing.

My current solution is this:  
`.add_student` can take two kinds of arguments - a `Student` object or the arguments to construct one. The way I’m doing this is to have `Student`'s ` __init__ ` method take a `name` positional parameter, and ` **kwargs`, since I’m fine with adding Students with just a name and adding more info later, but then I have to remove the name parameter from kwargs, lest I get a TypeError:** init**() got multiple values for argument ‘name’:

```
def add_student(self, student: [Student] = None, **kwargs: Any):
           if student and isinstance(student, Student):
        self.students.append(student)
    else:
        # if name := kwargs.get('name') isinstance(name, str): Python 3.8
        name = kwargs.pop('name', None)
        if isinstance(name, str):
            self.students.append(Student(name, **kwargs))

```

It would be nice if I could make the `name` parameter to `Student` positional only, since it’s the only argument that would be supplied, and thus the name key in `kwargs` would be ignored.

The other advantage in this situation that I see is that if I make the `student` parameter in the `.add_student` method positional only, I won’t have a clash if I add a `student` kwarg to the `Student` class (for what reason I don’t know, maybe I want to be able to add a student with `self.name ='class_average'`, or `self.name='always in trouble'`, and `self.student = False`), which would insulate the `Class.add_student` method to any changes to `Student`'s additional arguments (decoupling, is that the term?).

---

<div class="post-metadata">

**Author:** ![steve.dower](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/steve.dower/32/56_2.png) [@steve.dower](https://discuss.python.org/u/steve.dower)\
**Post date:** [April 1, 2019, 2:15pm UTC](https://discuss.python.org/t/pep-570-python-positional-only-parameters/1078/118 "2019-04-01T14:15:09Z")

</div>

> [@toonarmycaptain](#):
>
> It would be nice if I could make the `name` parameter to Student positional only, since it’s the only argument that would be supplied, and thus the name key in kwargs would be ignored.

I think this may be a misunderstanding of the proposal, or at least the point where using it would end up making your code more complicated.

Today, you could simply pass all of kwargs as `Student(**kwargs)` and it will expand out name just as you have (though without the typecheck). And if name is missing, you’ll get the same error as if you called Student without providing it.

If you were to make name positional-only, you would be forcing yourself into having to extract it as you are here. And any additional positional-only parameters would mean changing all of these calls to ensure that the arguments are correctly forwarded. (Using`**kwargs` as you have is actually a fairly common pattern to forward “known” arguments in a kwargs to avoid having to make changes in many places.)

Your case for potentially wanting to use “student” as an argument to Student is legitimate. That’s the fmt and self examples that we’re figuring out how to deal with. Making “student” in “add\_student” be positional only would be one way to deal with this, but I’m not prepared to say that’s the _best_ way.

---

<div class="post-metadata">

**Author:** ![toonarmycaptain](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/toonarmycaptain/32/183_2.png) [@toonarmycaptain](https://discuss.python.org/u/toonarmycaptain)\
**Post date:** [April 1, 2019, 2:22pm UTC](https://discuss.python.org/t/pep-570-python-positional-only-parameters/1078/119 "2019-04-01T14:22:15Z")

</div>

Ok, so while I was researching and double checking my reply here I found that I could use:  
`self.students.append(Student(**kwargs))` and it works fine (this is after finding I could use `dict.pop(key, default)` instead of assigning the value then using `del dict['key']` to delete the key. So I am learning today!

I believe my point about insulating positional and kwargs from name clashes, particularly when taking arguments that might be reliant on other code, still stands.

…and, I see you replied with what I found while I was writing my reply! Cheers.

---

<div class="post-metadata">

**Author:** ![steve.dower](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/steve.dower/32/56_2.png) [@steve.dower](https://discuss.python.org/u/steve.dower)\
**Post date:** [April 1, 2019, 2:29pm UTC](https://discuss.python.org/t/pep-570-python-positional-only-parameters/1078/120 "2019-04-01T14:29:32Z")

</div>

> [@toonarmycaptain](#):
>
> So I am learning today!

Honestly, I think this is the best thing to have happened so far in this thread 🙂 (and I’m even more glad it was self-learning and not just from my reply)

[Previous page](https://discuss.python.org/t/pep-570-python-positional-only-parameters/1078.md?page=5)

[Next page](https://discuss.python.org/t/pep-570-python-positional-only-parameters/1078.md?page=7)
