Add kwdefaults parameter to function constructor

I was recently playing around with decorators and experimenting with defining a function's signature dynamically at runtime, and came across the builtins.function class constructor (more easily accessible through the types.FunctionType alias). I quickly realized, however, that even though the constructor has a parameter (argdefs) that is used to specify default values for the resulting function's positional arguments, there is no corresponding parameter for keyword-only argument defaults. This seems like a glaring omission, especially considering the fact that argdefs takes a tuple that is directly assigned (unmodified) to the __defaults__ attribute. I can't find any obvious reason why there shouldn't be a similar "kwdefs" parameter that takes a dict and assigns it to __kwdefaults__. I downloaded the cpython repo, made this change myself as proof-of-concept, and compiled it, and it appears to work fine. This brings me to two questions: 1. Is there a reason for this disparity that I'm not seeing (e.g. breaking some other feature), or is it just an oversight? 2. If I wanted to submit this as an actual language change, would I need to write a full PEP or is it small enough that it could go to the issue tracker? (Note that the documentation says this constructor can vary between implementations, so the change would only apply to cpython if that matters.) Also, if this is the wrong place to ask this, please feel free to set me straight; I'm completely new to this whole process, so any help on where to start would be appreciated.

First of all, thank you for telling me this. I didn't even know that positional-only parameters existed at all until a few days ago when I discovered them while exploring this issue, let alone that they had been added to Python functions in 3.8. Second, after poking around a bit in 3.8, it looks like the positional-only args don't actually impact the __defaults__ attribute (or the argdefs parameter). This is pretty much what I expected when I initially read your message, since the positional-only parameters are part of the same ordered set as the normal positional parameters. In a regular function signature, having a default positional followed by a non-default positional is still a SyntaxError, regardless of where the positional-only split is; this means all default positionals are still consecutive and it still only needs one tuple to specify their values. This was a good question to ask, though, since that feature definitely seemed like something that might be problematic; I'll be sure to rebase my changes from 3.7 onto 3.8 to make sure nothing else in the update breaks them. On Fri, Oct 18, 2019 at 9:34 AM Anders Hovmöller <boxed@killingar.net> wrote:

The implementation starts here: https://github.com/python/cpython/blob/ecb035cd14c11521276343397151929a94018... The argument clinic input specifying the signature is a few lines above. Clinic's output is here: https://github.com/python/cpython/blob/master/Objects/clinic/funcobject.c.h I suspect that the omission is just an oversight. You should probably just open a bug on bugs.python.org. If you feel like contributing code, not just bug reports, try working on a pull request! (See the devguide: https://devguide.python.org/) Good luck! On Fri, Oct 18, 2019 at 6:33 AM Gus Wiedey <guswiedey@gmail.com> wrote:
-- --Guido van Rossum (python.org/~guido) *Pronouns: he/him **(why is my pronoun here?)* <http://feministing.com/2015/02/03/how-using-they-as-a-singular-pronoun-can-c...>

I actually have a commit already made, but I realized there is one possible complication that I may have overlooked: if there are keys in __kwdefaults__ that don't correspond to any explicitly-named arguments in the signature, will those get ignored or could they cause problems? On Fri, Oct 18, 2019 at 2:11 PM Guido van Rossum <guido@python.org> wrote:

On Oct 18, 2019, at 12:17, Gus Wiedey <guswiedey@gmail.com> wrote:
I actually have a commit already made, but I realized there is one possible complication that I may have overlooked: if there are keys in __kwdefaults__ that don't correspond to any explicitly-named arguments in the signature, will those get ignored or could they cause problems?
Aren’t __defaults__ and __kwdefaults__ mutable, so this exact same issue can arise today? I think it’s worth testing anyway (and testing both with and without a **kw, and maybe testing what happens with too many __defaults__ too), but unless the result is something like “the constructor segfaults”, it seems like probably it’s fine to keep doing it, and if not it’s probably a separate bug from the one you’re fixing.

First of all, thank you for telling me this. I didn't even know that positional-only parameters existed at all until a few days ago when I discovered them while exploring this issue, let alone that they had been added to Python functions in 3.8. Second, after poking around a bit in 3.8, it looks like the positional-only args don't actually impact the __defaults__ attribute (or the argdefs parameter). This is pretty much what I expected when I initially read your message, since the positional-only parameters are part of the same ordered set as the normal positional parameters. In a regular function signature, having a default positional followed by a non-default positional is still a SyntaxError, regardless of where the positional-only split is; this means all default positionals are still consecutive and it still only needs one tuple to specify their values. This was a good question to ask, though, since that feature definitely seemed like something that might be problematic; I'll be sure to rebase my changes from 3.7 onto 3.8 to make sure nothing else in the update breaks them. On Fri, Oct 18, 2019 at 9:34 AM Anders Hovmöller <boxed@killingar.net> wrote:

The implementation starts here: https://github.com/python/cpython/blob/ecb035cd14c11521276343397151929a94018... The argument clinic input specifying the signature is a few lines above. Clinic's output is here: https://github.com/python/cpython/blob/master/Objects/clinic/funcobject.c.h I suspect that the omission is just an oversight. You should probably just open a bug on bugs.python.org. If you feel like contributing code, not just bug reports, try working on a pull request! (See the devguide: https://devguide.python.org/) Good luck! On Fri, Oct 18, 2019 at 6:33 AM Gus Wiedey <guswiedey@gmail.com> wrote:
-- --Guido van Rossum (python.org/~guido) *Pronouns: he/him **(why is my pronoun here?)* <http://feministing.com/2015/02/03/how-using-they-as-a-singular-pronoun-can-c...>

I actually have a commit already made, but I realized there is one possible complication that I may have overlooked: if there are keys in __kwdefaults__ that don't correspond to any explicitly-named arguments in the signature, will those get ignored or could they cause problems? On Fri, Oct 18, 2019 at 2:11 PM Guido van Rossum <guido@python.org> wrote:

On Oct 18, 2019, at 12:17, Gus Wiedey <guswiedey@gmail.com> wrote:
I actually have a commit already made, but I realized there is one possible complication that I may have overlooked: if there are keys in __kwdefaults__ that don't correspond to any explicitly-named arguments in the signature, will those get ignored or could they cause problems?
Aren’t __defaults__ and __kwdefaults__ mutable, so this exact same issue can arise today? I think it’s worth testing anyway (and testing both with and without a **kw, and maybe testing what happens with too many __defaults__ too), but unless the result is something like “the constructor segfaults”, it seems like probably it’s fine to keep doing it, and if not it’s probably a separate bug from the one you’re fixing.
participants (4)
-
Anders Hovmöller
-
Andrew Barnert
-
Guido van Rossum
-
Gus Wiedey