[Python-ideas] Keyword only argument on function call

Steve Barnes gadgetsteve at live.co.uk
Wed Sep 12 16:14:37 EDT 2018

On 12/09/2018 16:38, Steven D'Aprano wrote:
> On Wed, Sep 12, 2018 at 03:58:25PM +0100, Jonathan Fine wrote:
>> My question is about correctly implementing of __params__ as a keyword
>> identifier, with semantics as in Steve B's code snippet above.
> The semantics of Steve's code snippet are ambiguous.
>> Here's my question: Do you think implementing this requires the
>> avoidance of a race hazard?
> I don't know what "this" is any more. I thought Steve wanted an
> externally accessible fn.__params__ dict, as that's what he said he
> wanted, but his code snippet doesn't show that.
> If there is no externally accessible fn.__params__ dict, then there's no
> race hazard. I see no reason why a __params__ local variable would be
> subject to race conditions. But as you so rightly quoted the Zen at me
> for guessing in the face of ambiguity, without knowing what Steve
> intends, I can't answer your question.
> As a purely internal local variable, it would still have the annoyance
> that writing to the dict might not actually effect the local values, the
> same issue that locals() has. But if we cared enough, we could make the
> dict a proxy rather than a real dict.
> I see no reason why __params__ must be treated as special keyword, like
> __debug__, although given that it is involved in special compiler magic,
> that might be prudent.
> (Although, in sufficient old versions of Python, even __debug__ was just
> a regular name.)
>> Or perhaps it can be done, as I suggested,
>> entirely within the execution frame on the stack?
> Indeed.
> Like I said right at the start, there shouldn't be any problem for the
> compiler adding a local variable to each function (or just when
> required) containing the initial arguments bound to the function
> parameters. *How* the compiler does it, whether it is done during
> compilation or on entry to the function call, or something else, is an
> implementation detail which presumably each Python interpreter can
> choose for itself.
> All of this presumes that it is a desirable feature.

My intent with the __params__, (or whatever it might end up being 
called), was to provide a mechanism whereby we could:

a) find out, before calling, which parameters a function/method accepts, 
(just as __defaults__ gives us which values the function/method has 
default values for so does not require in every call with its defaults). 
Since this would normally be a compile time operation I do not 
anticipate any race conditions. I suspect that this would also be of 
great use to IDE authors and others as well as the use case on this thread.

b) a convenient mechanism for accessing all of the supplied 
parameters/arguments, (whether actually given or from defaults), from 
within the function/method both the parameter names and the values 
supplied at the time of the specific call. The example I gave was a 
rough and ready filtering of the outer functions parameters down to 
those that are accepted by the function that is about to be called, (I 
suspect that __locals__() might have been a better choice here). I don't 
anticipate race conditions here either as the values would be local at 
this point.

The idea was to provide a similar mechanism to the examples of functions 
that accept a list and dictionary in addition to the parameters that 
they do consume so as to be able to work with parameter 
lists/dictionaries that exceed the requirements. The difference is that, 
since we can query the function/method for what parameters it accepts 
and filter what we have to match, we do not need to alter the signature 
of the called item. This is important when providing wrappers for code 
that we do not have the freedom to alter.

I have done a little testing and found that:
  a) if we have a fn(a, b, c) and call it with fn(b=2, c=3, a=1) it is 
quite happy and assigns the correct values so constructing a dictionary 
that satisfies all of the required parameters and calling with 
fn(**the_dict) is fine.
  b) Calling dir() or __locals__() on the first line of the function 
gives the required information (but blocks the docstring which would be 
a bad idea).

The one worry is how to get the required parameter/argument list for 
overloaded functions or methods but AFAIK these are all calls to wrapped 
C/C++/other items so already take (*arg, **argv) inputs. I would guess 
that we would need some sort of indicator for this type of function.

I hope I have made my thoughts clearer rather than muddier :-) thank you 
all for taking the time to think about this.
Steve (Gadget) Barnes
Any opinions in this message are my personal opinions and do not reflect 
those of my employer.

This email has been checked for viruses by AVG.

More information about the Python-ideas mailing list