[Python-Dev] Review of PEP 362 (signature object)
Yury Selivanov
yselivanov.ml at gmail.com
Tue Mar 13 15:35:10 CET 2012
Guido, Brett,
I've tried to use the proposed signature object, however, I found that
the 'bind' method is incorrect, and came up with my own implementation
of the PEP: https://gist.github.com/2029032 (If needed, I can change
the licence to PSFL) I used my version to implement typechecking,
arguments validation in various RPC dispatch mechanisms, and it is
proven to work.
First of all, in the current version of the PEP, "bind" doesn't work
correctly with "varargs", as it returns a dictionary object:
def foo(bar, *args):
print(bar, args)
s = signature(foo)
bound = s.bind(1, 2 ,3 ,4)
print('Bound args:', bound)
foo(**bound)
This code outputs the following:
Bound args: {'args': (2, 3, 4), 'bar': 1}
Traceback (most recent call last):
File "test.py", line 286, in <module>
foo(**bound)
TypeError: foo() got an unexpected keyword argument 'args'
The conclusion is that ** form of unpacking is not always enough, so
'bind' should at least return a pair of (args, kwargs).
Secondly, I don't think that even (args, kwargs) pair is enough, as
some information about how arguments were mapped is lost. In my
implementation, 'bind' method returns an instance of 'BoundArguments'
class, which preserves the exact mapping, and has two convenience
properties '.args' and '.kwargs', so the example above transforms into:
bound = s.bind(1, 2, 3, 4)
foo(*bound.args, **bound.kwargs)
And that works as it should. When some advanced processing is required,
you can work with its private fields:
>>> bound._args
(1,)
>>> bound._varargs
(2, 3, 4)
I also think that keyword-only arguments deserve to land in a separate
collection in the signature object, in my implementation it is
'signature.kwonlyargs' slot. It is easier to do some advanced processing
of arguments this way, and even the 'signature.__iter__' is simpler.
Finally, I also added 'render_args' method to the signature. It just
renders function's arguments as in its definition:
>>> signature(foo).render_args()
bar, *args
This is useful for printing detailed error messages and hints.
-
Yury
More information about the Python-Dev
mailing list