[Python-Dev] AC Derby and accepting None for optional positional arguments

Guido van Rossum guido at python.org
Thu Jan 16 06:37:09 CET 2014

Well, I think these are mostly artifacts from old times, and usually
passing None *should* be the same as omitting the argument. But check each

On Wednesday, January 15, 2014, Larry Hastings <larry at hastings.org> wrote:

> On 01/15/2014 08:35 PM, Ryan Smith-Roberts wrote:
>  On Wed, Jan 15, 2014 at 7:57 PM, Ryan Smith-Roberts <rmsr at lab.net<javascript:_e({}, 'cvml', 'rmsr at lab.net');>
> > wrote:
>>  socket.getservbyname(servicename[, protocolname])
>> ->
>> socket.getservbyname(servicename, protocolname=None)
>  Here is a more complicated example, since the above does technically
> have an alternative fix:
>  sockobj.sendmsg(buffers[, ancdata[, flags[, address]]])
> ->
> sockobj.sendmsg(buffers, ancdata=None, flags=0, address=None)
> I feel like Ryan didn't sufficiently explain the problem.  I'll elaborate.
> For functions implemented in Python, it's always true that:
>    - a parameter that is optional always has a default value, and
>    - this default value is visible to Python and is a Python value.
> The default value of every parameter is part of the function's
> signature--you can see them with inspect.signature() or
> inspect.getfullargspec().
> A corollary of this: for every function implemented in Python, you can
> construct a call to it where you fill in every optional value with its
> published default value, and this is exactly equivalent to calling it
> without specifying those arguments:
> def foo(a=any_python_value): ...
> sig = inspect.signature(foo)
> defaults = [p.default for p in sig.parameters.values()]
> foo(*defaults) == foo()
> Assuming neither foo nor "any_python_value" have side effects, those two
> calls to foo() will be exactly the same in every way.
> But!  Builtin functions implemented in C commonly have optional parameters
> whose default value is not only opaque to Python, it's not renderable as a
> Python value.  That default value is NULL.  Consider the first two
> paragraphs of SHA1_new() in Modules/sha1module.c:
> static PyObject *
> SHA1_new(PyObject *self, PyObject *args, PyObject *kwdict)
> {
>     static char *kwlist[] = {"string", NULL};
>     SHA1object *new;
>     PyObject *data_obj = NULL;
>     Py_buffer buf;
>     if (!PyArg_ParseTupleAndKeywords(args, kwdict, "|O:new", kwlist,
>                                      &data_obj)) {
>         return NULL;
>     }
> ...
> The "string" parameter is optional.  Its value, if specified, is written
> to "data_obj".  "data_obj" has a default value of NULL.  There is no Python
> value you could pass in to this function that would result in "data_obj"
> being (redundantly) set to NULL.  In Python SHA1_new is known as
> "_sha1.sha1".  And:
> sig = inspect.signature(_sha1.sha1)
> defaults = [p.default for p in sig.parameters.values()]
> _sha1.sha1(*defaults) == _sha1.sha1()
> There's no value we could put in the signature for _sha1.sha1 that would
> behave exactly the same as that NULL.
> The ultimate goal of Argument Clinic is to provide introspection
> information for builtins.  But we can't provide a default value to Python
> for the "string" parameter to _sha1.sha1() without changing the semantics
> of the function.  We're stuck.
> Ryan's question, then, is "can we change a function like this so it
> accepts None?"  My initial reaction is "no".  That might be okay for
> _sha1.sha1(), but it'd be best to avoid.
> In the specific case of SHA1_new's "string" parameter, we could lie and
> claim that the default value is b''.  Internally we could still use NULL as
> a default and get away with it.  But this is only a happy coincidence.
> Many (most?) functions like this won't have a clever Python value we can
> trick you with.
> What else could we do?  We could add a special value, let's call it
> sys.NULL, whose specific semantics are "turns into NULL when passed into
> builtins".  This would solve the problem but it's really, really awful.
> The only other option I can see: don't convert SHA1_new() to use Argument
> Clinic, and don't provide introspection information for it either.
> Can you, gentle reader, suggest a better option?
> */arry*
> p.s. Ryan's function signatures above suggest that he's converting code
> from using PyArg_ParseTuple into using PyArg_ParseTupleAndKeywords.  I
> don't think he's *actually* doing that, and if I saw that in patches
> submitted to me I would ask that it be fixed.

--Guido van Rossum (on iPad)
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/python-dev/attachments/20140115/820d40ba/attachment.html>

More information about the Python-Dev mailing list