[Python-Dev] Updated PEP 362 (Function Signature Object)
Mark Shannon
mark at hotpy.org
Wed Jun 6 17:50:15 CEST 2012
Steven D'Aprano wrote:
> Brett Cannon wrote:
>
>> PEP: 362
>> Title: Function Signature Object
>> Version: $Revision$
>> Last-Modified: $Date$
>> Author: Brett Cannon <brett at python.org>, Jiwon Seo <seojiwon at gmail.com>,
>> Yury Selivanov <yselivanov at sprymix.com>, Larry Hastings <
>> larry at hastings.org>
>> Status: Draft
>> Type: Standards Track
>> Content-Type: text/x-rst
>> Created: 21-Aug-2006
>> Python-Version: 3.3
>> Post-History: 04-Jun-2012
>>
>>
>> Abstract
>> ========
>>
>> Python has always supported powerful introspection capabilities,
>> including introspecting functions and methods. (For the rest of
>> this PEP, "function" refers to both functions and methods). By
>> examining a function object you can fully reconstruct the function's
>> signature. Unfortunately this information is stored in an inconvenient
>> manner, and is spread across a half-dozen deeply nested attributes.
>>
>> This PEP proposes a new representation for function signatures.
>> The new representation contains all necessary information about a
>> function
>> and its parameters, and makes introspection easy and straightforward.
>
> It's already easy and straightforward, thanks to the existing
> inspect.getfullargspec function. If this existing inspect function is
> lacking something, the PEP should explain what, and why the inspect
> function can't be fixed.
>
>
>> However, this object does not replace the existing function
>> metadata, which is used by Python itself to execute those
>> functions. The new metadata object is intended solely to make
>> function introspection easier for Python programmers.
>
> What happens when the existing function metadata and the __signature__
> object disagree?
>
> Are there use-cases where we want them to disagree, or is disagreement
> always a sign that something is broken?
>
>
>
>> Signature Object
>> ================
>>
>> A Signature object represents the overall signature of a function.
>> It stores a `Parameter object`_ for each parameter accepted by the
>> function, as well as information specific to the function itself.
>
> There's a considerable amount of data recorded, including a number of
> mappings (dicts?). This potentially increase the size of functions, and
> the overhead of creating them. Since most functions are never
> introspected, or only rarely introspected, it seems rather wasteful to
> record all this data "just in case", particularly since it's already
> recorded once in the function metadata and/or code object.
>
I agree with Stephen. Don't forget that each list comprehension
evaluation involves creating a temporary function object.
>
>
>> A Signature object has the following public attributes and methods:
>>
>> * name : str
>> Name of the function.
>
> Functions already record their name (twice!), and it is simple enough to
> query func.__name__. What reason is there for recording it a third time,
> in the Signature object?
>
> Besides, I don't consider the name of the function part of the
> function's signature. Functions can have multiple names, or no name at
> all, and the calling signature remains the same.
>
> Even if we limit the discussion to distinct functions (rather than a
> single function with multiple names), I consider spam(x, y, z) ham(x, y,
> z) and eggs(x, y, z) to have the same signature. Otherwise, it makes it
> difficult to talk about one function having the same signature as
> another function, unless they also have the same name. Which would be
> unfortunate.
>
>
>> * qualname : str
>> Fully qualified name of the function.
>
> What's the fully qualified name of the function, and why is it needed?
>
>
>
> [...]
>> The structure of the Parameter object is:
>
>> * is_args : bool
>> True if the parameter accepts variable number of arguments
>> (``\*args``-like), else False.
>
>
> "args" is just a common name for the parameter, not for the kind of
> parameter. *args (or *data, *whatever) is a varargs parameter, and so
> the attribute should be called "is_varargs".
>
>
>> * is_kwargs : bool
>> True if the parameter accepts variable number of keyword
>> arguments (``\*\*kwargs``-like), else False.
>
> Likewise for **kwargs (or **kw, etc.) I'm not sure if there is a common
> convention for keyword varargs, so I see two options:
>
> is_varkwargs
> is_kwvarargs
>
>
>> * is_implemented : bool
>> True if the parameter is implemented for use. Some platforms
>> implement functions but can't support specific parameters
>> (e.g. "mode" for os.mkdir). Passing in an unimplemented
>> parameter may result in the parameter being ignored,
>> or in NotImplementedError being raised. It is intended that
>> all conditions where ``is_implemented`` may be False be
>> thoroughly documented.
>
> What to do about parameters which are partly implemented? E.g.
> mode='spam' is implemented but mode='ham' is not.
>
> Is there a use-case for is_implemented?
>
> [...]
>> Annotation Checker
>
>> def check_type(sig, arg_name, arg_type, arg_value):
>> # Internal function that incapsulates arguments type checking
>
> /s/incapsulates/encapsulates
>
>
>
>> Open Issues
>> ===========
>
> inspect.getfullargspec is currently unable to introspect builtin
> functions and methods. Should builtins gain a __signature__ so they can
> be introspected?
I'm +0 on this, but care is needed as print and [].append are the same
type in CPython.
>
>
>
>> When to construct the Signature object?
>> ---------------------------------------
>>
>> The Signature object can either be created in an eager or lazy
>> fashion. In the eager situation, the object can be created during
>> creation of the function object. In the lazy situation, one would
>> pass a function object to a function and that would generate the
>> Signature object and store it to ``__signature__`` if
>> needed, and then return the value of ``__signature__``.
>>
>> In the current implementation, signatures are created only on demand
>> ("lazy").
>
> +1
+1 also. See comment above about list comprehensions
>
>
>
>> Deprecate ``inspect.getfullargspec()`` and ``inspect.getcallargs()``?
>> ---------------------------------------------------------------------
>
>
> -1
>
>> Since the Signature object replicates the use of ``getfullargspec()``
>> and ``getcallargs()`` from the ``inspect`` module it might make sense
>> to begin deprecating them in 3.3.
>
> I think it is way to soon to deprecate anything. I don't think we should
> even consider PendingDeprecation until at least 3.4.
>
> Actually, I would go further: leave getfullargspec to extract the
> *actual* argument spec from the code object, and __signature__ to be the
> claimed argument spec. Earlier, you state:
>
> "Changes to the Signature object, or to any of its data members,
> do not affect the function itself."
>
> which leaves the possibility that __signature__ may no longer match the
> actual argument spec, for some reason. If you remove getfullargspec,
> people will have to reinvent it to deal with such cases.
>
>
>
>
More information about the Python-Dev
mailing list