[Python-Dev] Review of PEP 362 (signature object) (original) (raw)
Yury Selivanov yselivanov.ml at gmail.com
Tue Mar 13 15:35:10 CET 2012
- Previous message: [Python-Dev] Review of PEP 362 (signature object)
- Next message: [Python-Dev] Docs of weak stdlib modules should encourage exploration of 3rd-party alternatives
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]
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
- Previous message: [Python-Dev] Review of PEP 362 (signature object)
- Next message: [Python-Dev] Docs of weak stdlib modules should encourage exploration of 3rd-party alternatives
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]