Login | Register For Free | Help
Search for: (Advanced)

Mailing List Archive: Python: Dev

PEP 362 Third Revision

 

 

First page Previous page 1 2 3 4 Next page Last page  View All Python dev RSS feed   Index | Next | Previous | View Threaded


yselivanov.ml at gmail

Jun 13, 2012, 7:52 PM

Post #1 of 84 (337 views)
Permalink
PEP 362 Third Revision

Hello,

The new revision of PEP 362 has been posted:
http://www.python.org/dev/peps/pep-0362/


Summary:

1. Signature object now represents the call signature of a
function. That said, it doesn't have 'name' and 'qualname'
attributes anymore, and can be tested for equality against
other signatures.

2. signature() function support all kinds of callables:
classes, metaclasses, methods, class- & staticmethods,
'functools.partials', and callable objects. If a callable
object has a '__signature__' attribute it does a deepcopy
of it before return.

3. No implicit caching to __signature__.

4. Added 'Signature.bind_partial' and 'Signature.format'
methods.

A patch with the PEP implementation is attached to the
issue 15008. It should be ready for code review.


Thank you!



PEP: 362
Title: Function Signature Object
Version: $Revision$
Last-Modified: $Date$
Author: Brett Cannon <brett [at] python>, Jiwon Seo <seojiwon [at] gmail>,
Yury Selivanov <yselivanov [at] sprymix>, Larry Hastings <larry [at] hastings>
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.

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.


Signature Object
================

A Signature object represents the call signature of a function and
its return annotation. For each parameter accepted by the function
it stores a `Parameter object`_ in its ``parameters`` collection.

A Signature object has the following public attributes and methods:

* return_annotation : object
The annotation for the return type of the function if specified.
If the function has no annotation for its return type, this
attribute is not set.
* parameters : OrderedDict
An ordered mapping of parameters' names to the corresponding
Parameter objects (keyword-only arguments are in the same order
as listed in ``code.co_varnames``).
* bind(\*args, \*\*kwargs) -> BoundArguments
Creates a mapping from positional and keyword arguments to
parameters. Raises a ``BindError`` (subclass of ``TypeError``)
if the passed arguments do not match the signature.
* bind_partial(\*args, \*\*kwargs) -> BoundArguments
Works the same way as ``bind()``, but allows the omission
of some required arguments (mimics ``functools.partial``
behavior.)
* format(...) -> str
Formats the Signature object to a string. Optional arguments allow
for custom render functions for parameter names,
annotations and default values, along with custom separators.

Signature implements the ``__str__`` method, which fallbacks to the
``Signature.format()`` call.

It's possible to test Signatures for equality. Two signatures
are equal when they have equal parameters and return annotations.

Changes to the Signature object, or to any of its data members,
do not affect the function itself.


Parameter Object
================

Python's expressive syntax means functions can accept many different
kinds of parameters with many subtle semantic differences. We
propose a rich Parameter object designed to represent any possible
function parameter.

The structure of the Parameter object is:

* name : str
The name of the parameter as a string.
* default : object
The default value for the parameter, if specified. If the
parameter has no default value, this attribute is not set.
* annotation : object
The annotation for the parameter if specified. If the
parameter has no annotation, this attribute is not set.
* is_keyword_only : bool
True if the parameter is keyword-only, else False.
* is_args : bool
True if the parameter accepts variable number of arguments
(``*args``-like), else False.
* is_kwargs : bool
True if the parameter accepts variable number of keyword
arguments (``**kwargs``-like), else False.
* 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.

Two parameters are equal when all their attributes are equal.


BoundArguments Object
=====================

Result of a ``Signature.bind`` call. Holds the mapping of arguments
to the function's parameters.

Has the following public attributes:

* arguments : OrderedDict
An ordered, mutable mapping of parameters' names to arguments' values.
Does not contain arguments' default values.
* args : tuple
Tuple of positional arguments values. Dynamically computed from
the 'arguments' attribute.
* kwargs : dict
Dict of keyword arguments values. Dynamically computed from
the 'arguments' attribute.

The ``arguments`` attribute should be used in conjunction with
``Signature.parameters`` for any arguments processing purposes.

``args`` and ``kwargs`` properties can be used to invoke functions:
::

def test(a, *, b):
...

sig = signature(test)
ba = sig.bind(10, b=20)
test(*ba.args, **ba.kwargs)


Implementation
==============

The implementation adds a new function ``signature()`` to the ``inspect``
module. The function is the preferred way of getting a ``Signature`` for
a callable object.

The function implements the following algorithm:

- If the object is not callable - raise a TypeError

- If the object has a ``__signature__`` attribute and if it
is not ``None`` - return a deepcopy of it

- If it is ``None`` and the object is an instance of
``BuiltinFunction``, raise a ``ValueError``

- If the object is a an instance of ``FunctionType``:

- If it has a ``__wrapped__`` attribute, return
``signature(object.__wrapped__)``

- Or else construct a new ``Signature`` object and return it

- If the object is a method or a classmethod, construct and return
a new ``Signature`` object, with its first parameter (usually
``self`` or ``cls``) removed

- If the object is a staticmethod, construct and return
a new ``Signature`` object

- If the object is an instance of ``functools.partial``, construct
a new ``Signature`` from its ``partial.func`` attribute, and
account for already bound ``partial.args`` and ``partial.kwargs``

- If the object is a class or metaclass:

- If the object's type has a ``__call__`` method defined in
its MRO, return a Signature for it

- If the object has a ``__new__`` method defined in its class,
return a Signature object for it

- If the object has a ``__init__`` method defined in its class,
return a Signature object for it

- Return ``signature(object.__call__)``

Note, that the ``Signature`` object is created in a lazy manner, and
is not automatically cached. If, however, the Signature object was
explicitly cached by the user, ``signature()`` returns a new deepcopy
of it on each invocation.

An implementation for Python 3.3 can be found at [#impl]_.
The python issue tracking the patch is [#issue]_.


Design Considerations
=====================

No implicit caching of Signature objects
----------------------------------------

The first PEP design had a provision for implicit caching of ``Signature``
objects in the ``inspect.signature()`` function. However, this has the
following downsides:

* If the ``Signature`` object is cached then any changes to the function
it describes will not be reflected in it. However, If the caching is
needed, it can be always done manually and explicitly

* It is better to reserve the ``__signature__`` attribute for the cases
when there is a need to explicitly set to a ``Signature`` object that
is different from the actual one


Examples
========

Visualizing Callable Objects' Signature
---------------------------------------
::

from inspect import signature
from functools import partial, wraps


class FooMeta(type):
def __new__(mcls, name, bases, dct, *, bar:bool=False):
return super().__new__(mcls, name, bases, dct)

def __init__(cls, name, bases, dct, **kwargs):
return super().__init__(name, bases, dct)


class Foo(metaclass=FooMeta):
def __init__(self, spam:int=42):
self.spam = spam

def __call__(self, a, b, *, c) -> tuple:
return a, b, c


print('FooMeta >', str(signature(FooMeta)))
print('Foo >', str(signature(Foo)))
print('Foo.__call__ >', str(signature(Foo.__call__)))
print('Foo().__call__ >', str(signature(Foo().__call__)))
print('partial(Foo().__call__, 1, c=3) >',
str(signature(partial(Foo().__call__, 1, c=3))))
print('partial(partial(Foo().__call__, 1, c=3), 2, c=20) >',
str(signature(partial(partial(Foo().__call__, 1, c=3), 2, c=20))))


The script will output:
::

FooMeta > (name, bases, dct, *, bar:bool=False)
Foo > (spam:int=42)
Foo.__call__ > (self, a, b, *, c) -> tuple
Foo().__call__ > (a, b, *, c) -> tuple
partial(Foo().__call__, 1, c=3) > (b, *, c=3) -> tuple
partial(partial(Foo().__call__, 1, c=3), 2, c=20) > (*, c=20) -> tuple


Annotation Checker
------------------
::

import inspect
import functools

def checktypes(func):
'''Decorator to verify arguments and return types

Example:

>>> @checktypes
... def test(a:int, b:str) -> int:
... return int(a * b)

>>> test(10, '1')
1111111111

>>> test(10, 1)
Traceback (most recent call last):
...
ValueError: foo: wrong type of 'b' argument, 'str' expected, got 'int'
'''

sig = inspect.signature(func)

types = {}
for param in sig.parameters.values():
# Iterate through function's parameters and build the list of
# arguments types
try:
type_ = param.annotation
except AttributeError:
continue
else:
if not inspect.isclass(type_):
# Not a type, skip it
continue

types[param.name] = type_

# If the argument has a type specified, let's check that its
# default value (if present) conforms with the type.
try:
default = param.default
except AttributeError:
continue
else:
if not isinstance(default, type_):
raise ValueError("{func}: wrong type of a default value for {arg!r}". \
format(func=sig.qualname, arg=param.name))

def check_type(sig, arg_name, arg_type, arg_value):
# Internal function that incapsulates arguments type checking
if not isinstance(arg_value, arg_type):
raise ValueError("{func}: wrong type of {arg!r} argument, " \
"{exp!r} expected, got {got!r}". \
format(func=sig.qualname, arg=arg_name,
exp=arg_type.__name__, got=type(arg_value).__name__))

@functools.wraps(func)
def wrapper(*args, **kwargs):
# Let's bind the arguments
ba = sig.bind(*args, **kwargs)
for arg_name, arg in ba.arguments.items():
# And iterate through the bound arguments
try:
type_ = types[arg_name]
except KeyError:
continue
else:
# OK, we have a type for the argument, lets get the corresponding
# parameter description from the signature object
param = sig.parameters[arg_name]
if param.is_args:
# If this parameter is a variable-argument parameter,
# then we need to check each of its values
for value in arg:
check_type(sig, arg_name, type_, value)
elif param.is_kwargs:
# If this parameter is a variable-keyword-argument parameter:
for subname, value in arg.items():
check_type(sig, arg_name + ':' + subname, type_, value)
else:
# And, finally, if this parameter a regular one:
check_type(sig, arg_name, type_, arg)

result = func(*ba.args, **ba.kwargs)
# The last bit - let's check that the result is correct
try:
return_type = sig.return_annotation
except AttributeError:
# Looks like we don't have any restriction on the return type
pass
else:
if isinstance(return_type, type) and not isinstance(result, return_type):
raise ValueError('{func}: wrong return type, {exp} expected, got {got}'. \
format(func=sig.qualname, exp=return_type.__name__,
got=type(result).__name__))
return result

return wrapper


References
==========

.. [#impl] pep362 branch (https://bitbucket.org/1st1/cpython/overview)
.. [#issue] issue 15008 (http://bugs.python.org/issue15008)


Copyright
=========

This document has been placed in the public domain.

..
Local Variables:
mode: indented-text
indent-tabs-mode: nil
sentence-end-double-space: t
fill-column: 70
coding: utf-8
End:

_______________________________________________
Python-Dev mailing list
Python-Dev [at] python
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: http://mail.python.org/mailman/options/python-dev/list-python-dev%40lists.gossamer-threads.com


yselivanov at gmail

Jun 13, 2012, 8:06 PM

Post #2 of 84 (335 views)
Permalink
Re: PEP 362 Third Revision [In reply to]

On 2012-06-13, at 10:52 PM, Yury Selivanov wrote:
> 2. signature() function support all kinds of callables:
> classes, metaclasses, methods, class- & staticmethods,
> 'functools.partials', and callable objects. If a callable
> object has a '__signature__' attribute it does a deepcopy
> of it before return.


Properly decorated functions are also supported.

-
Yury
_______________________________________________
Python-Dev mailing list
Python-Dev [at] python
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: http://mail.python.org/mailman/options/python-dev/list-python-dev%40lists.gossamer-threads.com


ncoghlan at gmail

Jun 13, 2012, 9:17 PM

Post #3 of 84 (332 views)
Permalink
Re: PEP 362 Third Revision [In reply to]

On Thu, Jun 14, 2012 at 1:06 PM, Yury Selivanov <yselivanov [at] gmail> wrote:
> On 2012-06-13, at 10:52 PM, Yury Selivanov wrote:
>> 2. signature() function support all kinds of callables:
>> classes, metaclasses, methods, class- & staticmethods,
>> 'functools.partials', and callable objects.  If a callable
>> object has a '__signature__' attribute it does a deepcopy
>> of it before return.
>
>
> Properly decorated functions are also supported.

I'd like to see the "shared state" decorator from the previous thread
included, as well as a short interactive interpreter session showing
correct reporting of the signature of functools.partial instances.

Cheers,
Nick.

--
Nick Coghlan   |   ncoghlan [at] gmail   |   Brisbane, Australia
_______________________________________________
Python-Dev mailing list
Python-Dev [at] python
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: http://mail.python.org/mailman/options/python-dev/list-python-dev%40lists.gossamer-threads.com


alexandre.zani at gmail

Jun 13, 2012, 9:29 PM

Post #4 of 84 (330 views)
Permalink
Re: PEP 362 Third Revision [In reply to]

On Wed, Jun 13, 2012 at 8:06 PM, Yury Selivanov <yselivanov [at] gmail> wrote:
> On 2012-06-13, at 10:52 PM, Yury Selivanov wrote:
>> 2. signature() function support all kinds of callables:
>> classes, metaclasses, methods, class- & staticmethods,
>> 'functools.partials', and callable objects.  If a callable
>> object has a '__signature__' attribute it does a deepcopy
>> of it before return.
>
>
> Properly decorated functions are also supported.
>
> -
> Yury
> _______________________________________________
> Python-Dev mailing list
> Python-Dev [at] python
> http://mail.python.org/mailman/listinfo/python-dev
> Unsubscribe: http://mail.python.org/mailman/options/python-dev/alexandre.zani%40gmail.com

This is really exciting! A couple questions/points:

Why do we look at __wrapped__ only if the object is a FunctionType?
Why not support __wrapped__ on all callables?

Why special-case functools.partial? Couldn't functools.partial just
set __signature__ itself? Is that because of inspect's dependency on
functools?

Just a thought: Do we want to include the docstring? A function's
docstring is often intimately tied to its signature. (Or at least, a
lot of us try to write docstrings that effectively describe the
function's signature)
_______________________________________________
Python-Dev mailing list
Python-Dev [at] python
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: http://mail.python.org/mailman/options/python-dev/list-python-dev%40lists.gossamer-threads.com


ncoghlan at gmail

Jun 14, 2012, 3:00 AM

Post #5 of 84 (326 views)
Permalink
Re: PEP 362 Third Revision [In reply to]

On Jun 14, 2012 2:31 PM, "Alexandre Zani" <alexandre.zani [at] gmail> wrote:

> Why do we look at __wrapped__ only if the object is a FunctionType?
> Why not support __wrapped__ on all callables?

Fair question - duck typing here makes more sense to me, too.

>
> Why special-case functools.partial? Couldn't functools.partial just
> set __signature__ itself? Is that because of inspect's dependency on
> functools?

Got it in one. Really, it's the same reason we don't burden the builtin
callable machinery with it - to ensure the dependencies only flow in one
direction.

> Just a thought: Do we want to include the docstring? A function's
> docstring is often intimately tied to its signature. (Or at least, a
> lot of us try to write docstrings that effectively describe the
> function's signature)

No, combining the signature with other details like the name and docstring
is the task of higher level interfaces like pydoc.

Cheers,
Nick.

--
Sent from my phone, thus the relative brevity :)


yselivanov at gmail

Jun 14, 2012, 4:45 AM

Post #6 of 84 (324 views)
Permalink
Re: PEP 362 Third Revision [In reply to]

On 2012-06-14, at 12:17 AM, Nick Coghlan wrote:

> On Thu, Jun 14, 2012 at 1:06 PM, Yury Selivanov <yselivanov [at] gmail> wrote:
>> On 2012-06-13, at 10:52 PM, Yury Selivanov wrote:
>>> 2. signature() function support all kinds of callables:
>>> classes, metaclasses, methods, class- & staticmethods,
>>> 'functools.partials', and callable objects. If a callable
>>> object has a '__signature__' attribute it does a deepcopy
>>> of it before return.
>>
>>
>> Properly decorated functions are also supported.
>
> I'd like to see the "shared state" decorator from the previous thread
> included, as well as a short interactive interpreter session showing
> correct reporting of the signature of functools.partial instances.


OK. Below is how I want to update the PEP. Do you want to include
anything else?


Visualizing Callable Objects' Signatures
----------------------------------------

Let's define some classes and functions:

::

from inspect import signature
from functools import partial, wraps


class FooMeta(type):
def __new__(mcls, name, bases, dct, *, bar:bool=False):
return super().__new__(mcls, name, bases, dct)

def __init__(cls, name, bases, dct, **kwargs):
return super().__init__(name, bases, dct)


class Foo(metaclass=FooMeta):
def __init__(self, spam:int=42):
self.spam = spam

def __call__(self, a, b, *, c) -> tuple:
return a, b, c


def shared_vars(*shared_args):
"""Decorator factory that defines shared variables that are
passed to every invocation of the function"""

def decorator(f):
@wraps(f)
def wrapper(*args, **kwds):
full_args = shared_args + args
return f(*full_args, **kwds)
# Override signature
sig = wrapper.__signature__ = signature(f)
for __ in shared_args:
sig.parameters.popitem(last=False)
return wrapper
return decorator


@shared_vars({})
def example(_state, a, b, c):
return _state, a, b, c


def format_signature(obj):
return str(signature(obj))


Now, in the python REPL:

::

>>> format_signature(FooMeta)
'(name, bases, dct, *, bar:bool=False)'

>>> format_signature(Foo)
'(spam:int=42)'

>>> format_signature(Foo.__call__)
'(self, a, b, *, c) -> tuple'

>>> format_signature(Foo().__call__)
'(a, b, *, c) -> tuple'

>>> format_signature(partial(Foo().__call__, 1, c=3))
'(b, *, c=3) -> tuple'

>>> format_signature(partial(partial(Foo().__call__, 1, c=3), 2, c=20))
'(*, c=20) -> tuple'

>>> format_signature(example)
'(a, b, c)'

>>> format_signature(partial(example, 1, 2))
'(c)'

>>> format_signature(partial(partial(example, 1, b=2), c=3))
'(b=2, c=3)'


-
Yury
_______________________________________________
Python-Dev mailing list
Python-Dev [at] python
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: http://mail.python.org/mailman/options/python-dev/list-python-dev%40lists.gossamer-threads.com


yselivanov at gmail

Jun 14, 2012, 4:50 AM

Post #7 of 84 (325 views)
Permalink
Re: PEP 362 Third Revision [In reply to]

On 2012-06-14, at 12:29 AM, Alexandre Zani wrote:
> Why do we look at __wrapped__ only if the object is a FunctionType?
> Why not support __wrapped__ on all callables?

Good idea ;) I'll add this.

Thanks,
-
Yury
_______________________________________________
Python-Dev mailing list
Python-Dev [at] python
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: http://mail.python.org/mailman/options/python-dev/list-python-dev%40lists.gossamer-threads.com


victor.stinner at gmail

Jun 14, 2012, 5:06 AM

Post #8 of 84 (325 views)
Permalink
Re: PEP 362 Third Revision [In reply to]

Sorry if I'm asking dummy questions, I didn't follow the discussion.

> * format(...) -> str
>    Formats the Signature object to a string.  Optional arguments allow
>    for custom render functions for parameter names,
>    annotations and default values, along with custom separators.

Hum, what are these "custom render functions"? Can you give an example?

> * is_keyword_only : bool
>    True if the parameter is keyword-only, else False.
> * is_args : bool
>    True if the parameter accepts variable number of arguments
>    (``*args``-like), else False.
> * is_kwargs : bool
>    True if the parameter accepts variable number of keyword
>    arguments (``**kwargs``-like), else False.

Hum, why not using a attribute with a string value instead of 3
attribute? For example:
* argtype: "index", "varargs", "keyword" or "keyword_only"

It would avoid a possible inconsitency (ex: is_args=True and
is_kwargs=True). And it would help to implement something like a C
switch/case using a dict: argtype => function for functions using
signatures.

> * 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.

I suppose that the value depends on the running platform? (For
example, you may get a different value on Linux and Windows.)

> Implementation
> ==============
>
>    - If the object has a ``__signature__`` attribute and if it
>      is not ``None`` - return a deepcopy of it

Oh, why copying the object? It may impact performances. If fhe caller
knows that it will modify the signature, it can deepcopy the
signature.

>        - If it is ``None`` and the object is an instance of
>          ``BuiltinFunction``, raise a ``ValueError``

What about builtin functions (ex: len)? Do you plan to add a
__signature__ attribute? If yes, something created on demand or
created at startup?

It would be nice to have a C API to create Signature objects, maybe
from the same format string than PyArg_Parse*() functions. But it can
be implemented later.

Is it possible to build a Signature object from a string describing
the prototype (ex: "def f(x, y): pass")? (I mean: do you plan to add
such function?)

--

Except of these remarks, I like this PEP :-)

Victor
_______________________________________________
Python-Dev mailing list
Python-Dev [at] python
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: http://mail.python.org/mailman/options/python-dev/list-python-dev%40lists.gossamer-threads.com


ncoghlan at gmail

Jun 14, 2012, 5:15 AM

Post #9 of 84 (327 views)
Permalink
Re: PEP 362 Third Revision [In reply to]

Looks great!

One very minor quibble is that I prefer 'ns' to 'dct' for the namespace
parameter in a metaclass, but that doesn't really matter for the PEP.

--
Sent from my phone, thus the relative brevity :)
On Jun 14, 2012 9:45 PM, "Yury Selivanov" <yselivanov [at] gmail> wrote:

> On 2012-06-14, at 12:17 AM, Nick Coghlan wrote:
>
> > On Thu, Jun 14, 2012 at 1:06 PM, Yury Selivanov <yselivanov [at] gmail>
> wrote:
> >> On 2012-06-13, at 10:52 PM, Yury Selivanov wrote:
> >>> 2. signature() function support all kinds of callables:
> >>> classes, metaclasses, methods, class- & staticmethods,
> >>> 'functools.partials', and callable objects. If a callable
> >>> object has a '__signature__' attribute it does a deepcopy
> >>> of it before return.
> >>
> >>
> >> Properly decorated functions are also supported.
> >
> > I'd like to see the "shared state" decorator from the previous thread
> > included, as well as a short interactive interpreter session showing
> > correct reporting of the signature of functools.partial instances.
>
>
> OK. Below is how I want to update the PEP. Do you want to include
> anything else?
>
>
> Visualizing Callable Objects' Signatures
> ----------------------------------------
>
> Let's define some classes and functions:
>
> ::
>
> from inspect import signature
> from functools import partial, wraps
>
>
> class FooMeta(type):
> def __new__(mcls, name, bases, dct, *, bar:bool=False):
> return super().__new__(mcls, name, bases, dct)
>
> def __init__(cls, name, bases, dct, **kwargs):
> return super().__init__(name, bases, dct)
>
>
> class Foo(metaclass=FooMeta):
> def __init__(self, spam:int=42):
> self.spam = spam
>
> def __call__(self, a, b, *, c) -> tuple:
> return a, b, c
>
>
> def shared_vars(*shared_args):
> """Decorator factory that defines shared variables that are
> passed to every invocation of the function"""
>
> def decorator(f):
> @wraps(f)
> def wrapper(*args, **kwds):
> full_args = shared_args + args
> return f(*full_args, **kwds)
> # Override signature
> sig = wrapper.__signature__ = signature(f)
> for __ in shared_args:
> sig.parameters.popitem(last=False)
> return wrapper
> return decorator
>
>
> @shared_vars({})
> def example(_state, a, b, c):
> return _state, a, b, c
>
>
> def format_signature(obj):
> return str(signature(obj))
>
>
> Now, in the python REPL:
>
> ::
>
> >>> format_signature(FooMeta)
> '(name, bases, dct, *, bar:bool=False)'
>
> >>> format_signature(Foo)
> '(spam:int=42)'
>
> >>> format_signature(Foo.__call__)
> '(self, a, b, *, c) -> tuple'
>
> >>> format_signature(Foo().__call__)
> '(a, b, *, c) -> tuple'
>
> >>> format_signature(partial(Foo().__call__, 1, c=3))
> '(b, *, c=3) -> tuple'
>
> >>> format_signature(partial(partial(Foo().__call__, 1, c=3), 2, c=20))
> '(*, c=20) -> tuple'
>
> >>> format_signature(example)
> '(a, b, c)'
>
> >>> format_signature(partial(example, 1, 2))
> '(c)'
>
> >>> format_signature(partial(partial(example, 1, b=2), c=3))
> '(b=2, c=3)'
>
>
> -
> Yury


yselivanov.ml at gmail

Jun 14, 2012, 6:50 AM

Post #10 of 84 (321 views)
Permalink
Re: PEP 362 Third Revision [In reply to]

On 2012-06-14, at 8:06 AM, Victor Stinner wrote:
> Sorry if I'm asking dummy questions, I didn't follow the discussion.
>
>> * format(...) -> str
>> Formats the Signature object to a string. Optional arguments allow
>> for custom render functions for parameter names,
>> annotations and default values, along with custom separators.
>
> Hum, what are these "custom render functions"? Can you give an example?

That's how the function looks right now (I'm not sure we should load
the PEP with this):

def format(self, *, format_name=str,
format_default=repr,
format_annotation=formatannotation,
format_args=(lambda param: '*' + str(param)),
format_kwargs=(lambda param: '**' + str(param)),

token_params_separator=', ',
token_kwonly_separator='*',
token_left_paren='(',
token_right_paren=')',
token_colon=':',
token_eq='=',
token_return_annotation=' -> '):

'''Format signature to a string.

Arguments (all optional):

* format_name : A function to format names of parameters. Parameter
won't be rendered if ``None`` is returned.
* format_default : A function to format default values of parameters.
Default value won't be rendered if ``None`` is returned.
* format_annotation : A function to format parameter annotations.
Annotation won't be rendered if ``None`` is returned.
* format_args : A function to render ``*args`` like parameters.
Parameter won't be rendered if ``None`` is returned.
* format_kwargs : A function to render ``**kwargs`` like parameters.
Parameter won't be rendered if ``None`` is returned.
* token_params_separator : A separator for parameters. Set to
', ' by default.
* token_kwonly_separator : A separator for arguments and
keyword-only arguments. Defaults to '*'.
* token_left_paren : Left signature parenthesis, defaults to '('.
* token_right_paren : Left signature parenthesis, defaults to ')'.
* token_colon : Separates parameter from its annotation,
defaults to ':'.
* token_eq : Separates parameter from its default value, set to
'=' by default.
* token_return_annotation : Function return annotation, defaults
to ' -> '.
'''

I've designed it in such a way, that everything is configurable, so you
can render functions to color-term, HTML, or whatever else.

>> * is_keyword_only : bool
>> True if the parameter is keyword-only, else False.
>> * is_args : bool
>> True if the parameter accepts variable number of arguments
>> (``*args``-like), else False.
>> * is_kwargs : bool
>> True if the parameter accepts variable number of keyword
>> arguments (``**kwargs``-like), else False.
>
> Hum, why not using a attribute with a string value instead of 3
> attribute? For example:
> * argtype: "index", "varargs", "keyword" or "keyword_only"
>
> It would avoid a possible inconsitency (ex: is_args=True and
> is_kwargs=True). And it would help to implement something like a C
> switch/case using a dict: argtype => function for functions using
> signatures.

Originally, I thought the the line:

if parameters.is_args

is better looking that:

if parameters.kind == 'vararg'

But, I like your arguments regarding inconsistency and dispatch
through a dict (someone may find it useful). Also, Larry gave
another one - who knows if we add another type of arguments in
the future.

I guess if nobody really wants to keep 'is_args', we can alter the
PEP.

Let's consider replacement of 'Parameter.is_*' set of attributes with
a single 'Parameter.kind' attribute, which will have the following
possible values: 'positional', 'vararg', 'keyword-only', 'varkwarg'.

(I think 'positional' is more intuitive than 'index'?)

>> * 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.
>
> I suppose that the value depends on the running platform? (For
> example, you may get a different value on Linux and Windows.)

Correct.

>> Implementation
>> ==============
>>
>> - If the object has a ``__signature__`` attribute and if it
>> is not ``None`` - return a deepcopy of it
>
> Oh, why copying the object? It may impact performances. If fhe caller
> knows that it will modify the signature, it can deepcopy the
> signature.

There was a discussion on this topic earlier on python-dev.
In short - as we usually create new signatures with each 'signature()'
call, users will expect that they can modify those freely. But if we
have one defined in __signature__, without copying it, all its
modifications will be persistent across 'signature()' calls. So the
deepcopy here is required more for the consistency reasons. Besides,
I don't think that 'signature()' will be used extensively in
performance-critical types of code. And even if it is - you can just
cache it manually.

>> - If it is ``None`` and the object is an instance of
>> ``BuiltinFunction``, raise a ``ValueError``
>
> What about builtin functions (ex: len)? Do you plan to add a
> __signature__ attribute? If yes, something created on demand or
> created at startup?

Larry is going to add signatures to some 'os' module functions. But
that would it for 3.3, I guess.

> It would be nice to have a C API to create Signature objects, maybe
> from the same format string than PyArg_Parse*() functions. But it can
> be implemented later.

Then parameters will lack the 'name' attribute. I think we need another
approach here.

> Is it possible to build a Signature object from a string describing
> the prototype (ex: "def f(x, y): pass")? (I mean: do you plan to add
> such function?)


There are no plans to add it now (no good reasons to include such
functionality in 3.3 at least)

Thank you,

-
Yury
_______________________________________________
Python-Dev mailing list
Python-Dev [at] python
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: http://mail.python.org/mailman/options/python-dev/list-python-dev%40lists.gossamer-threads.com


alexandre.zani at gmail

Jun 14, 2012, 7:50 AM

Post #11 of 84 (322 views)
Permalink
Re: PEP 362 Third Revision [In reply to]

On Thu, Jun 14, 2012 at 6:50 AM, Yury Selivanov <yselivanov.ml [at] gmail> wrote:
> On 2012-06-14, at 8:06 AM, Victor Stinner wrote:
>> Sorry if I'm asking dummy questions, I didn't follow the discussion.
>>
>>> * format(...) -> str
>>>    Formats the Signature object to a string.  Optional arguments allow
>>>    for custom render functions for parameter names,
>>>    annotations and default values, along with custom separators.
>>
>> Hum, what are these "custom render functions"? Can you give an example?
>
> That's how the function looks right now (I'm not sure we should load
> the PEP with this):
>
>    def format(self, *, format_name=str,
>                        format_default=repr,
>                        format_annotation=formatannotation,
>                        format_args=(lambda param: '*' + str(param)),
>                        format_kwargs=(lambda param: '**' + str(param)),
>
>                        token_params_separator=', ',
>                        token_kwonly_separator='*',
>                        token_left_paren='(',
>                        token_right_paren=')',
>                        token_colon=':',
>                        token_eq='=',
>                        token_return_annotation=' -> '):
>
>        '''Format signature to a string.
>
>        Arguments (all optional):
>
>        * format_name : A function to format names of parameters.  Parameter
>          won't be rendered if ``None`` is returned.
>        * format_default : A function to format default values of parameters.
>          Default value won't be rendered if ``None`` is returned.
>        * format_annotation : A function to format parameter annotations.
>          Annotation won't be rendered if ``None`` is returned.
>        * format_args : A function to render ``*args`` like parameters.
>          Parameter won't be rendered if ``None`` is returned.
>        * format_kwargs : A function to render ``**kwargs`` like parameters.
>          Parameter won't be rendered if ``None`` is returned.
>        * token_params_separator : A separator for parameters.  Set to
>          ', ' by default.
>        * token_kwonly_separator : A separator for arguments and
>          keyword-only arguments.  Defaults to '*'.
>        * token_left_paren : Left signature parenthesis, defaults to '('.
>        * token_right_paren : Left signature parenthesis, defaults to ')'.
>        * token_colon : Separates parameter from its annotation,
>          defaults to ':'.
>        * token_eq : Separates parameter from its default value, set to
>          '=' by default.
>        * token_return_annotation : Function return annotation, defaults
>          to ' -> '.
>        '''
>
> I've designed it in such a way, that everything is configurable, so you
> can render functions to color-term, HTML, or whatever else.
>
>>> * is_keyword_only : bool
>>>    True if the parameter is keyword-only, else False.
>>> * is_args : bool
>>>    True if the parameter accepts variable number of arguments
>>>    (``*args``-like), else False.
>>> * is_kwargs : bool
>>>    True if the parameter accepts variable number of keyword
>>>    arguments (``**kwargs``-like), else False.
>>
>> Hum, why not using a attribute with a string value instead of 3
>> attribute? For example:
>> * argtype: "index", "varargs", "keyword" or "keyword_only"
>>
>> It would avoid a possible inconsitency (ex: is_args=True and
>> is_kwargs=True). And it would help to implement something like a C
>> switch/case using a dict: argtype => function for functions using
>> signatures.
>
> Originally, I thought the the line:
>
>   if parameters.is_args
>
> is better looking that:
>
>   if parameters.kind == 'vararg'
>
> But, I like your arguments regarding inconsistency and dispatch
> through a dict (someone may find it useful).  Also, Larry gave
> another one - who knows if we add another type of arguments in
> the future.
>
> I guess if nobody really wants to keep 'is_args', we can alter the
> PEP.
>
> Let's consider replacement of 'Parameter.is_*' set of attributes with
> a single 'Parameter.kind' attribute, which will have the following
> possible values: 'positional', 'vararg', 'keyword-only', 'varkwarg'.
>
> (I think 'positional' is more intuitive than 'index'?)
>

I disagree largely for readability reasons. As the PEP stands, I can
look at a Parameter object and immediately understand what the
different possible values are by just listing its attributes. The kind
attribute makes that harder.

Comparing with strings is error prone. If I do param.is_varargs
(adding an s at the end of the attribute name) I will see an attribute
error and know what is going on. If I do the same mistake with the
kind attribute param.kind == "varargs", the expression will just
always be False without any explanation.

>>> * 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.
>>
>> I suppose that the value depends on the running platform? (For
>> example, you may get a different value on Linux and Windows.)
>
> Correct.
>
>>> Implementation
>>> ==============
>>>
>>>    - If the object has a ``__signature__`` attribute and if it
>>>      is not ``None`` - return a deepcopy of it
>>
>> Oh, why copying the object? It may impact performances. If fhe caller
>> knows that it will modify the signature, it can deepcopy the
>> signature.
>
> There was a discussion on this topic earlier on python-dev.
> In short - as we usually create new signatures with each 'signature()'
> call, users will expect that they can modify those freely.  But if we
> have one defined in __signature__, without copying it, all its
> modifications will be persistent across 'signature()' calls.  So the
> deepcopy here is required more for the consistency reasons.  Besides,
> I don't think that 'signature()' will be used extensively in
> performance-critical types of code.  And even if it is - you can just
> cache it manually.
>
>>>        - If it is ``None`` and the object is an instance of
>>>          ``BuiltinFunction``, raise a ``ValueError``
>>
>> What about builtin functions (ex: len)? Do you plan to add a
>> __signature__ attribute? If yes, something created on demand or
>> created at startup?
>
> Larry is going to add signatures to some 'os' module functions. But
> that would it for 3.3, I guess.
>
>> It would be nice to have a C API to create Signature objects, maybe
>> from the same format string than PyArg_Parse*() functions. But it can
>> be implemented later.
>
> Then parameters will lack the 'name' attribute.  I think we need another
> approach here.
>
>> Is it possible to build a Signature object from a string describing
>> the prototype (ex: "def f(x, y): pass")? (I mean: do you plan to add
>> such function?)
>
>
> There are no plans to add it now (no good reasons to include such
> functionality in 3.3 at least)
>
> Thank you,
>
> -
> Yury
> _______________________________________________
> Python-Dev mailing list
> Python-Dev [at] python
> http://mail.python.org/mailman/listinfo/python-dev
> Unsubscribe: http://mail.python.org/mailman/options/python-dev/alexandre.zani%40gmail.com
_______________________________________________
Python-Dev mailing list
Python-Dev [at] python
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: http://mail.python.org/mailman/options/python-dev/list-python-dev%40lists.gossamer-threads.com


alexandre.zani at gmail

Jun 14, 2012, 7:54 AM

Post #12 of 84 (321 views)
Permalink
Re: PEP 362 Third Revision [In reply to]

Thanks. :)

On Thu, Jun 14, 2012 at 4:50 AM, Yury Selivanov <yselivanov [at] gmail> wrote:
> On 2012-06-14, at 12:29 AM, Alexandre Zani wrote:
>> Why do we look at __wrapped__ only if the object is a FunctionType?
>> Why not support __wrapped__ on all callables?
>
> Good idea ;)  I'll add this.
>
> Thanks,
> -
> Yury
_______________________________________________
Python-Dev mailing list
Python-Dev [at] python
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: http://mail.python.org/mailman/options/python-dev/list-python-dev%40lists.gossamer-threads.com


yselivanov.ml at gmail

Jun 14, 2012, 8:05 AM

Post #13 of 84 (321 views)
Permalink
Re: PEP 362 Third Revision [In reply to]

On 2012-06-14, at 10:50 AM, Alexandre Zani wrote:
> On Thu, Jun 14, 2012 at 6:50 AM, Yury Selivanov <yselivanov.ml [at] gmail> wrote:
>> I guess if nobody really wants to keep 'is_args', we can alter the
>> PEP.
>>
>> Let's consider replacement of 'Parameter.is_*' set of attributes with
>> a single 'Parameter.kind' attribute, which will have the following
>> possible values: 'positional', 'vararg', 'keyword-only', 'varkwarg'.
>>
>> (I think 'positional' is more intuitive than 'index'?)
>>
>
> I disagree largely for readability reasons. As the PEP stands, I can
> look at a Parameter object and immediately understand what the
> different possible values are by just listing its attributes. The kind
> attribute makes that harder.
>
> Comparing with strings is error prone. If I do param.is_varargs
> (adding an s at the end of the attribute name) I will see an attribute
> error and know what is going on. If I do the same mistake with the
> kind attribute param.kind == "varargs", the expression will just
> always be False without any explanation.

Agree on this one, good point (although unit tests generally help to
avoid those problems.)

-
Yury
_______________________________________________
Python-Dev mailing list
Python-Dev [at] python
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: http://mail.python.org/mailman/options/python-dev/list-python-dev%40lists.gossamer-threads.com


rdmurray at bitdance

Jun 14, 2012, 8:06 AM

Post #14 of 84 (321 views)
Permalink
Re: PEP 362 Third Revision [In reply to]

On Thu, 14 Jun 2012 07:50:42 -0700, Alexandre Zani <alexandre.zani [at] gmail> wrote:
> On Thu, Jun 14, 2012 at 6:50 AM, Yury Selivanov <yselivanov.ml [at] gmail> wrote:
> > On 2012-06-14, at 8:06 AM, Victor Stinner wrote:
> >> Hum, why not using a attribute with a string value instead of 3
> >> attribute? For example:
> >> * argtype: "index", "varargs", "keyword" or "keyword_only"
> >>
> >> It would avoid a possible inconsitency (ex: is_args=True and
> >> is_kwargs=True). And it would help to implement something like a C
> >> switch/case using a dict: argtype => function for functions using
> >> signatures.
> >
> > Originally, I thought the the line:
> >
> >   if parameters.is_args
> >
> > is better looking that:
> >
> >   if parameters.kind == 'vararg'
> >
> > But, I like your arguments regarding inconsistency and dispatch
> > through a dict (someone may find it useful).  Also, Larry gave
> > another one - who knows if we add another type of arguments in
> > the future.
> >
> > I guess if nobody really wants to keep 'is_args', we can alter the
> > PEP.
> >
> > Let's consider replacement of 'Parameter.is_*' set of attributes with
> > a single 'Parameter.kind' attribute, which will have the following
> > possible values: 'positional', 'vararg', 'keyword-only', 'varkwarg'.
> >
> > (I think 'positional' is more intuitive than 'index'?)
> >
>
> I disagree largely for readability reasons. As the PEP stands, I can
> look at a Parameter object and immediately understand what the
> different possible values are by just listing its attributes. The kind
> attribute makes that harder.
>
> Comparing with strings is error prone. If I do param.is_varargs
> (adding an s at the end of the attribute name) I will see an attribute
> error and know what is going on. If I do the same mistake with the
> kind attribute param.kind == "varargs", the expression will just
> always be False without any explanation.

I don't have strong feelings about this, but to me the fact that there
are values of the individual parameters that if they occur on the same
object at the same time would be invalid is a code smell. If the thing
can be one and only one of a list of possible types, it makes sense to
me that this be indicated as a single attribute with a list of possible
values, rather than a set of boolean options, one for each type.

For the attribute error issue, we could have module attributes that give
names to the strings:

if parameter.kind == inspect.VARARG_KIND:
stuff

Or if we don't want that in the stdlib, the individual programmer who
cares about it can define their own constants.

--David


p.f.moore at gmail

Jun 14, 2012, 8:14 AM

Post #15 of 84 (321 views)
Permalink
Re: PEP 362 Third Revision [In reply to]

On 14 June 2012 15:50, Alexandre Zani <alexandre.zani [at] gmail> wrote:
> Comparing with strings is error prone. If I do param.is_varargs
> (adding an s at the end of the attribute name) I will see an attribute
> error and know what is going on. If I do the same mistake with the
> kind attribute param.kind == "varargs", the expression will just
> always be False without any explanation.

Agreed. Particularly in this case, a lot of the possible values are
far from completely standardised terms, so misspellings are quite
possible. Apart from the varargs case mentioned, I'd have to look at
the docs to know what name was used for the kind of a "normal"
parameter.

To be honest, I'm not too keen in is_args/is_kwargs as names, but they
are short and match common usage. I could go with is_vararg and
is_kwarg (or is_varargs and is_kwargs, but I hate the abbreviation
varkwarg :-)) because they are closer parallels, but either way this
is trivial bikeshedding, not worth spending time on.

If anyone *really* wants a "kind" string, parameter_kind(param) isn't
hard to define in your app, and you can choose your own terms...

So my view is -1 to a "kind" parameter, and +1 to the current is_XXX
names simply because there's no point bikeshedding.

Oh, and +1 to the PEP as a whole :-)

Paul.
_______________________________________________
Python-Dev mailing list
Python-Dev [at] python
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: http://mail.python.org/mailman/options/python-dev/list-python-dev%40lists.gossamer-threads.com


brett at python

Jun 14, 2012, 8:24 AM

Post #16 of 84 (321 views)
Permalink
Re: PEP 362 Third Revision [In reply to]

On Thu, Jun 14, 2012 at 9:50 AM, Yury Selivanov <yselivanov.ml [at] gmail>wrote:

[SNIP]
>
>

> Let's consider replacement of 'Parameter.is_*' set of attributes with
> a single 'Parameter.kind' attribute, which will have the following
> possible values: 'positional', 'vararg', 'keyword-only', 'varkwarg'.
>
> (I think 'positional' is more intuitive than 'index'?)
>
>
+1 if this change is made.

-Brett


ethan at stoneleaf

Jun 14, 2012, 8:52 AM

Post #17 of 84 (321 views)
Permalink
Re: PEP 362 Third Revision [In reply to]

Brett Cannon wrote:
>
>
> On Thu, Jun 14, 2012 at 9:50 AM, Yury Selivanov <yselivanov.ml [at] gmail
> <mailto:yselivanov.ml [at] gmail>> wrote:
>
> [SNIP]
>
>
>
> Let's consider replacement of 'Parameter.is_*' set of attributes with
> a single 'Parameter.kind' attribute, which will have the following
> possible values: 'positional', 'vararg', 'keyword-only', 'varkwarg'.
>
> (I think 'positional' is more intuitive than 'index'?)
>
>
> +1 if this change is made.

+1 to using 'kind', and another +1 to using 'kwarg' instead of 'varkwarg'.

~Ethan~
_______________________________________________
Python-Dev mailing list
Python-Dev [at] python
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: http://mail.python.org/mailman/options/python-dev/list-python-dev%40lists.gossamer-threads.com


ethan at stoneleaf

Jun 14, 2012, 9:03 AM

Post #18 of 84 (321 views)
Permalink
Re: PEP 362 Third Revision [In reply to]

Yury Selivanov wrote:
> Hello,
>
> The new revision of PEP 362 has been posted:
> http://www.python.org/dev/peps/pep-0362/
>
>
> It's possible to test Signatures for equality. Two signatures
> are equal when they have equal parameters and return annotations.

Possibly a dumb question, but do the parameter names have to be the same
to compare equal? If yes, is there an easy way to compare two
signatures by annotations alone?

~Ethan~
_______________________________________________
Python-Dev mailing list
Python-Dev [at] python
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: http://mail.python.org/mailman/options/python-dev/list-python-dev%40lists.gossamer-threads.com


yselivanov.ml at gmail

Jun 14, 2012, 9:16 AM

Post #19 of 84 (321 views)
Permalink
Re: PEP 362 Third Revision [In reply to]

On 2012-06-14, at 11:24 AM, Brett Cannon wrote:
> On Thu, Jun 14, 2012 at 9:50 AM, Yury Selivanov <yselivanov.ml [at] gmail> wrote:
>
> [SNIP]
>
> Let's consider replacement of 'Parameter.is_*' set of attributes with
> a single 'Parameter.kind' attribute, which will have the following
> possible values: 'positional', 'vararg', 'keyword-only', 'varkwarg'.
>
> (I think 'positional' is more intuitive than 'index'?)
>
>
> +1 if this change is made.

How about adding 'kind' and keeping 'is_*' attributes,
but making them read-only dynamic properties, i.e.:

class Parameter:
...

@property
def is_vararg(self):
return self.kind == 'vararg'

...

?

Thanks,
-
Yury

_______________________________________________
Python-Dev mailing list
Python-Dev [at] python
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: http://mail.python.org/mailman/options/python-dev/list-python-dev%40lists.gossamer-threads.com


benjamin at python

Jun 14, 2012, 9:32 AM

Post #20 of 84 (321 views)
Permalink
Re: PEP 362 Third Revision [In reply to]

2012/6/14 Yury Selivanov <yselivanov.ml [at] gmail>:
> On 2012-06-14, at 11:24 AM, Brett Cannon wrote:
>> On Thu, Jun 14, 2012 at 9:50 AM, Yury Selivanov <yselivanov.ml [at] gmail> wrote:
>>
>> [SNIP]
>>
>> Let's consider replacement of 'Parameter.is_*' set of attributes with
>> a single 'Parameter.kind' attribute, which will have the following
>> possible values: 'positional', 'vararg', 'keyword-only', 'varkwarg'.
>>
>> (I think 'positional' is more intuitive than 'index'?)
>>
>>
>> +1 if this change is made.
>
> How about adding 'kind' and keeping 'is_*' attributes,
> but making them read-only dynamic properties, i.e.:
>
>   class Parameter:
>       ...
>
>       @property
>       def is_vararg(self):
>           return self.kind == 'vararg'
>
>       ...
>
> ?

Seems a bit bloatly to me. (One way to do it.)


--
Regards,
Benjamin
_______________________________________________
Python-Dev mailing list
Python-Dev [at] python
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: http://mail.python.org/mailman/options/python-dev/list-python-dev%40lists.gossamer-threads.com


ethan at stoneleaf

Jun 14, 2012, 9:37 AM

Post #21 of 84 (321 views)
Permalink
Re: PEP 362 Third Revision [In reply to]

Yury Selivanov wrote:
> On 2012-06-14, at 11:24 AM, Brett Cannon wrote:
>> On Thu, Jun 14, 2012 at 9:50 AM, Yury Selivanov <yselivanov.ml [at] gmail> wrote:
>>
>> [SNIP]
>>
>> Let's consider replacement of 'Parameter.is_*' set of attributes with
>> a single 'Parameter.kind' attribute, which will have the following
>> possible values: 'positional', 'vararg', 'keyword-only', 'varkwarg'.
>>
>> (I think 'positional' is more intuitive than 'index'?)
>>
>>
>> +1 if this change is made.
>
> How about adding 'kind' and keeping 'is_*' attributes,
> but making them read-only dynamic properties, i.e.:
>
> class Parameter:
> ...
>
> @property
> def is_vararg(self):
> return self.kind == 'vararg'
>
> ...
>
> ?

I like it! +1!

~Ethan~
_______________________________________________
Python-Dev mailing list
Python-Dev [at] python
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: http://mail.python.org/mailman/options/python-dev/list-python-dev%40lists.gossamer-threads.com


yselivanov.ml at gmail

Jun 14, 2012, 9:39 AM

Post #22 of 84 (321 views)
Permalink
Re: PEP 362 Third Revision [In reply to]

On 2012-06-14, at 12:32 PM, Benjamin Peterson wrote:

> 2012/6/14 Yury Selivanov <yselivanov.ml [at] gmail>:
>> On 2012-06-14, at 11:24 AM, Brett Cannon wrote:
>>> On Thu, Jun 14, 2012 at 9:50 AM, Yury Selivanov <yselivanov.ml [at] gmail> wrote:
>>>
>>> [SNIP]
>>>
>>> Let's consider replacement of 'Parameter.is_*' set of attributes with
>>> a single 'Parameter.kind' attribute, which will have the following
>>> possible values: 'positional', 'vararg', 'keyword-only', 'varkwarg'.
>>>
>>> (I think 'positional' is more intuitive than 'index'?)
>>>
>>>
>>> +1 if this change is made.
>>
>> How about adding 'kind' and keeping 'is_*' attributes,
>> but making them read-only dynamic properties, i.e.:
>>
>> class Parameter:
>> ...
>>
>> @property
>> def is_vararg(self):
>> return self.kind == 'vararg'
>>
>> ...
>>
>> ?
>
> Seems a bit bloatly to me. (One way to do it.)

Yes, but on the other hand it solves "strings are error prone"
argument, keeps all 'is_*' attributes in sync, and makes them
read-only.

'kind' property may do validation on set, to diminish mistakes
probability even further.

-
Yury
_______________________________________________
Python-Dev mailing list
Python-Dev [at] python
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: http://mail.python.org/mailman/options/python-dev/list-python-dev%40lists.gossamer-threads.com


yselivanov.ml at gmail

Jun 14, 2012, 10:09 AM

Post #23 of 84 (321 views)
Permalink
Re: PEP 362 Third Revision [In reply to]

On 2012-06-14, at 12:03 PM, Ethan Furman wrote:

> Yury Selivanov wrote:
>> Hello,
>> The new revision of PEP 362 has been posted:
>> http://www.python.org/dev/peps/pep-0362/
>> It's possible to test Signatures for equality. Two signatures
>> are equal when they have equal parameters and return annotations.
>
> Possibly a dumb question, but do the parameter names have to be the same to compare equal? If yes, is there an easy way to compare two signatures by annotations alone?

Yes, parameter names have be the same.

You need to write a custom compare function for Parameters,
that will check that two have (or both don't) equal
annotations and *kinds*, and then write a compare function
for Signatures, that will test return_annotations and
'parameters' collections.

All in all, shouldn't be longer than 10-15 lines of code.

Another "solution" to the problem could be adding a new 'annotations'
read-only dynamic property to the Signature, that would iterate
through parameters and produce a single dict. But this solution
has a serious flaw, as signature of:

def foo(a:int, *, b:int) -> float

is not equal to the signature of:

def bar(a:int, b:int) -> float

and certainly not the signature of:

def spam(*args:int, **kwargs:int) -> float

So the most correct approach here is the one I described in the
first place.


Thanks,

-
Yury
_______________________________________________
Python-Dev mailing list
Python-Dev [at] python
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: http://mail.python.org/mailman/options/python-dev/list-python-dev%40lists.gossamer-threads.com


brett at python

Jun 14, 2012, 10:10 AM

Post #24 of 84 (321 views)
Permalink
Re: PEP 362 Third Revision [In reply to]

On Thu, Jun 14, 2012 at 12:39 PM, Yury Selivanov <yselivanov.ml [at] gmail>wrote:

> On 2012-06-14, at 12:32 PM, Benjamin Peterson wrote:
>
> > 2012/6/14 Yury Selivanov <yselivanov.ml [at] gmail>:
> >> On 2012-06-14, at 11:24 AM, Brett Cannon wrote:
> >>> On Thu, Jun 14, 2012 at 9:50 AM, Yury Selivanov <
> yselivanov.ml [at] gmail> wrote:
> >>>
> >>> [SNIP]
> >>>
> >>> Let's consider replacement of 'Parameter.is_*' set of attributes with
> >>> a single 'Parameter.kind' attribute, which will have the following
> >>> possible values: 'positional', 'vararg', 'keyword-only', 'varkwarg'.
> >>>
> >>> (I think 'positional' is more intuitive than 'index'?)
> >>>
> >>>
> >>> +1 if this change is made.
> >>
> >> How about adding 'kind' and keeping 'is_*' attributes,
> >> but making them read-only dynamic properties, i.e.:
> >>
> >> class Parameter:
> >> ...
> >>
> >> @property
> >> def is_vararg(self):
> >> return self.kind == 'vararg'
> >>
> >> ...
> >>
> >> ?
> >
> > Seems a bit bloatly to me. (One way to do it.)
>
> Yes, but on the other hand it solves "strings are error prone"
> argument, keeps all 'is_*' attributes in sync, and makes them
> read-only.
>
> 'kind' property may do validation on set, to diminish mistakes
> probability even further.
>

I agree with Benjamin, it goes against TOOWTDI without enough of a
justification to break the rule. Just make the strings constants on the
Parameter class and you solve the lack of enum issue.


alexandre.zani at gmail

Jun 14, 2012, 10:13 AM

Post #25 of 84 (323 views)
Permalink
Re: PEP 362 Third Revision [In reply to]

+1

On Thu, Jun 14, 2012 at 9:16 AM, Yury Selivanov <yselivanov.ml [at] gmail> wrote:
> On 2012-06-14, at 11:24 AM, Brett Cannon wrote:
>> On Thu, Jun 14, 2012 at 9:50 AM, Yury Selivanov <yselivanov.ml [at] gmail> wrote:
>>
>> [SNIP]
>>
>> Let's consider replacement of 'Parameter.is_*' set of attributes with
>> a single 'Parameter.kind' attribute, which will have the following
>> possible values: 'positional', 'vararg', 'keyword-only', 'varkwarg'.
>>
>> (I think 'positional' is more intuitive than 'index'?)
>>
>>
>> +1 if this change is made.
>
> How about adding 'kind' and keeping 'is_*' attributes,
> but making them read-only dynamic properties, i.e.:
>
>   class Parameter:
>       ...
>
>       @property
>       def is_vararg(self):
>           return self.kind == 'vararg'
>
>       ...
>
> ?
>
> Thanks,
> -
> Yury
>
> _______________________________________________
> Python-Dev mailing list
> Python-Dev [at] python
> http://mail.python.org/mailman/listinfo/python-dev
> Unsubscribe: http://mail.python.org/mailman/options/python-dev/alexandre.zani%40gmail.com
_______________________________________________
Python-Dev mailing list
Python-Dev [at] python
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: http://mail.python.org/mailman/options/python-dev/list-python-dev%40lists.gossamer-threads.com

First page Previous page 1 2 3 4 Next page Last page  View All Python dev RSS feed   Index | Next | Previous | View Threaded
 
 


Interested in having your list archived? Contact Gossamer Threads
 
  Web Applications & Managed Hosting Powered by Gossamer Threads Inc.