[Python-Dev] signature object issues (to discuss while I am out of contact)

Brett Cannon brett at python.org
Tue May 2 20:43:56 CEST 2006


On 5/2/06, Nick Coghlan <ncoghlan at gmail.com> wrote:
> Brett Cannon wrote:
> > One is whether a signature object should be automatically created for
> > every function.  As of right now the PEP I am drafting has it on a
> > per-need basis and have it assigned to __signature__ through a
> > built-in function or putting it 'inspect'.  Now automatically creating
> > the object would possibly make it more useful, but it could also be
> > considered overkill.  Also not doing it automatically allows signature
> > objects to possibly make more sense for classes (to represent
> > __init__) and instances (to represent __call__).  But having that same
> > support automatically feels off for some reason to me.
>
> My current impulse is to put the signature object in the inspect module to
> start with, and don't give it a special attribute at all.
>
> All of the use cases I can think of (introspection for documentation purposes
> or argument checking purposes) don't really suffer either way regardless of
> whether the signature retrieval is spelt "obj.__signature__" or
> "inspect.getsignature(obj)".
>

It does for  decorators.  How do you  make sure that a decorator uses 
the signature object of the wrapped function instead of the decorator?
 Or are you saying to just not worry about that right now?

> Since it doesn't make much difference from a usability point of view, let's
> start with the object in the library module first.
>
> > The second question is whether it is worth providing a function that
> > will either figure out if a tuple and dict representing arguments
> > would work in calling the function.  Some have even suggested a
> > function that returns the actual bindings if the call were to occur.
> > Personally I don't see a huge use for either, but even less for the
> > latter version.  If people have a legit use case for either please
> > speak up, otherwise I am tempted to keep the object simple.
>
> A "bind" method on the signature objects is pretty much essential for any kind
> of argument checking usage.
>
> In addition to Aahz's precondition checking example, Talin gave a good example
> on the Py3k list of a function decorator for logging all calls to a function,
> and including the argument bindings in the log message.
>
> And just in case you think the operation would be easy to implement if you
> need it, I've included below the bind method from the signature object I wrote
> to play around with the ideas posted to the Py3k list. It took a fair bit of
> work to get it to spit out the right answers :)
>

Thanks, Nick!

-Brett

> Cheers,
> Nick.
>
>      def bind(*args, **kwds):
>          """Return a dict mapping parameter names to bound arguments"""
>          self = args[0]
>          args = args[1:]
>          bound_params = {}
>          num_args = len(args)
>          missing_args = set(self.required_args)
>          arg_names = self.required_args + self.optional_args
>          num_names = len(arg_names)
>          # Handle excess positional arguments
>          if self.extra_args:
>              bound_params[self.extra_args] = tuple(args[num_names:])
>          elif num_args > num_names:
>              self._raise_args_error(num_args)
>          # Bind positional arguments
>          for name, value in zip(arg_names, args):
>              bound_params[name] = value
>              missing_args -= set((name,))
>          # Bind keyword arguments (and handle excess)
>          if self.extra_kwds:
>              extra_kwds = dict()
>              bound_params[self.extra_kwds] = extra_kwds
>          else:
>              extra_kwds = None
>          for name, value in kwds.items():
>              if name in bound_params:
>                  raise TypeError(
>                      "Got multiple values for argument '%s'" % name)
>              elif name in arg_names:
>                  missing_args -= set((name,))
>                  bound_params[name] = value
>              elif extra_kwds is not None:
>                  extra_kwds[name] = value
>              else:
>                  raise TypeError(
>                      "Got unexpected keyword argument '%s'" % name)
>          if missing_args:
>              self._raise_args_error(num_args)
>          # All done
>          return bound_params
>
>
> --
> Nick Coghlan   |   ncoghlan at gmail.com   |   Brisbane, Australia
> ---------------------------------------------------------------
>              http://www.boredomandlaziness.org
>


More information about the Python-Dev mailing list