[Python-ideas] Optional parameters without default value
Terry Reedy
tjreedy at udel.edu
Fri Mar 10 02:41:20 EST 2017
On 3/2/2017 3:03 AM, Serhiy Storchaka wrote:
> Function implemented in Python can have optional parameters with default
> value. It also can accept arbitrary number of positional and keyword
> arguments if use var-positional or var-keyword parameters (*args and
> **kwargs).
In other words, Python signature possibilities are already unusually
complex.
> But there is no way to declare an optional parameter that
> don't have default value.
... [moving the following up]
> I propose to add a new syntax for optional parameters. If the argument
> corresponding to the optional parameter without default value is not
> specified, the parameter takes no value.
-1
Being able to do this would violate what I believe is the fundamental
precondition for python-coded function bodies: all parameters are bound
to an object (so that using a parameter name is never a NameError); all
arguments are used exactly once in the binding process; the binding is
done without ambiguity (or resort to disambiguation rules). Calls that
prevent establishment of this precondition result in an exception.
This precondition is normal in computing languages. I believe that all
of the ~20 languages I have used over decades have had it. In any case,
I believe it is important in understanding Python signatures and calls,
and that there would need to be a strong reason to alter this
precondition. (Stronger than I judge the one given here to be.)
> Currently you need to use the sentinel idiom
which binds a special object to a parameter, thus fulfilling the
precondition.
> for implementing this:
>
> _sentinel = object()
> def get(store, key, default=_sentinel):
> if store.exists(key):
> return store.retrieve(key)
> if default is _sentinel:
> raise LookupError
> else:
> return default
>
> There are drawback of this:
>
> * Module's namespace is polluted with sentinel's variables.
If one cares, one can change the internal reference to 'get._sentinel'
and add
get._sentinel = _sentinel; del _sentinel
after the def (or package this in a decorator.
> * You need to check for the sentinel before passing it to other function
> by accident.
This might be a feature.
> * Possible name conflicts between sentinels for different functions of
> the same module.
Since None can be used as a sentinel for multiple functions, I don't
understand the problem you are pointing to.
> * Since the sentinel is accessible outside of the function, it possible
> to pass it to the function.
1. Give it a more private name (___private___?) similar to a reserved name.
2. Hide it better (as a object attribute, for instance).
> * help() of the function shows reprs of default values. "foo(bar=<object
> object at 0xb713c698>)" looks ugly.
Someone suggested a subclass of object with str = repr that prints
something like 'bar = <undefined>'. I think functools would be the
appropriate place for the class, predefined instance, and possibly a
decorator. Make the instance an attribute of the class so it a) would
have the same name both in the header and body, and b) would not be an
attribute of user module or user functions.
__
Terry Jan Reedy
More information about the Python-ideas
mailing list