On Thu, Dec 2, 2021 at 7:36 PM Paul Moore <p.f.mo...@gmail.com> wrote:
>
> Actually, Chris - does functools.wraps work properly in your
> implementation when wrapping functions with late-bound defaults?
>
> >>> def dec(f):
> ...     @wraps(f)
> ...     def inner(*args, **kw):
> ...         print("Calling")
> ...         return f(*args, **kw)
> ...     return inner
> ...
> >>> @dec
> ... def g(a => []):
> ...     return len(a)
>

Yes, it does. There are two things happening here which, from a
technical standpoint, are actually orthogonal; the function *call* is
simply using *a,**kw notation, so it's passing along all the
positional and keyword parameters untouched; but the function
*documentation* just says "hey look over there for the real
signature".

>>> g([1,2,3])
Calling
3
>>> g()
Calling
0

(In your example there's no proof that it's late-bound, but it is.)

>>> help(g)
Help on function g in module __main__:

g(a=>[])
>>> g.__wrapped__
<function g at 0x7fb5581efa00>
>>> g
<function g at 0x7fb5581efab0>

When you do "inner = wraps(f)(inner)", what happens is that the
function's name and qualname get updated, and then __wrapped__ gets
added as a pointer saying "hey, assume that I have the signature of
that guy over there". There's unfortunately no way to merge signatures
(you can't do something like "def f(*a, timeout=500, **kw):" and then
use the timeout parameter in your wrapper and pass the rest on -
help(f) will just show the base function's signature), and nothing is
actually aware of the underlying details.

But on the plus side, this DOES work correctly.

Documentation for late-bound defaults is done by a (compile-time)
string snapshot of the AST that defined the default, so it's about as
accurate as for early-bound defaults. One thing I'm not 100% happy
with in the reference implementation is that the string for help() is
stored on the function object, but the behaviour of the late-bound
default is inherent to the code object. I'm not sure of a way around
that, but it also doesn't seem terribly problematic in practice.

ChrisA
_______________________________________________
Python-ideas mailing list -- python-ideas@python.org
To unsubscribe send an email to python-ideas-le...@python.org
https://mail.python.org/mailman3/lists/python-ideas.python.org/
Message archived at 
https://mail.python.org/archives/list/python-ideas@python.org/message/TRDJLI24Z4BM3UCBVSV6E4FASDLT6CQY/
Code of Conduct: http://python.org/psf/codeofconduct/

Reply via email to