[Python-Dev] Updated PEP 362 (Function Signature Object)

Yury Selivanov yselivanov.ml at gmail.com
Fri Jun 8 06:04:19 CEST 2012


Nick,

I'm replying to your email (re 'functools.partial') in python-ideas here, 
in the PEP 362 thread, as my response raises some questions regarding its
design.

> On 2012-06-07, at 11:40 PM, Nick Coghlan wrote:
>> On Fri, Jun 8, 2012 at 12:57 PM, Yury Selivanov <yselivanov.ml at gmail.com> wrote:
>>> Hello,
>>> 
>>> While I was working on adding support for 'functools.partial' in PEP 362,
>>> I discovered that it doesn't do any sanity check on passed arguments
>>> upon creation.
>>> 
>>> Example:
>>> 
>>>    def foo(a):
>>>        pass
>>> 
>>>    p = partial(foo, 1, 2, 3) # this line will execute
>>> 
>>>    p() # this line will fail
>>> 
>>> Is it a bug?  Or is it a feature, because we deliberately don't do any checks
>>> because of performance issues?  If the latter - I think it should be at least
>>> documented.
>> 
>> Partly the latter, but also a matter of "this is hard to do, so we
>> don't even try". There are many other "lazy execution" APIs with the
>> same problem - they accept an arbitrary underlying callable, but you
>> don't find out until you try to call it that the arguments don't match
>> the parameters. This leads to errors being raised far away from the
>> code that actually introduced the error.
>> 
>> If you dig up some of the older PEP 362 discussions, you'll find that
>> allowing developers to reduce this problem over time is the main
>> reason the Signature.bind() method was added to the PEP. While I
>> wouldn't recommend it for the base partial type, I could easily see
>> someone using PEP 362 to create a "checked partial" that ensures
>> arguments are valid as they get passed in rather than leaving the
>> validation until the call is actually made.

It's not going to be that easy with the current PEP design.

In order to add support for partial, I had to split the implementation
of 'bind' into two functions:

    def _bind(self, args, kwargs, *, partial=False):
        ...

    def bind(self, *args, **kwargs):
        return self._bind(args, kwargs)

The first one, '_bind' does all the hard work.  When 'partial' flag
is False - it performs all possible checks.  But if it's 'True', then
it allows you to bind arguments in the same way 'functools.partial'
works, but still with most of the validation.

So:

    def foo(a, b, c):
        pass

    sig = signature(foo)
   
    sig._bind((1, 2, 3, 4), partial=True) # <- this will fail

    sig._bind((1, 2), partial=True) # <- this is OK

    sig._bind((1, 2), partial=False) # <- this will fail too


But the problem is - '_bind' is an implementation detail.

I'd like to discuss changing of PEP 362 'bind' signature to match
the '_bind' method. This will make API less nice, but will allow more.

Or, we can add something like 'bind_ex' (in addition to 'bind').

-
Yury


More information about the Python-Dev mailing list