Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > comp.lang.python > #110646 > unrolled thread
| Started by | Ben Finney <ben+python@benfinney.id.au> |
|---|---|
| First post | 2016-06-28 15:02 +1000 |
| Last post | 2016-07-01 23:53 -0600 |
| Articles | 13 on this page of 33 — 10 participants |
Back to article view | Back to comp.lang.python
This discussion starts older than the indexed window; earlier articles aren't shown. The article labeled Started by
below is the oldest one visible, not the original post.
Meta decorator with parameters, defined in explicit functions Ben Finney <ben+python@benfinney.id.au> - 2016-06-28 15:02 +1000
Re: Meta decorator with parameters, defined in explicit functions Paul Rubin <no.email@nospam.invalid> - 2016-06-27 23:08 -0700
Re: Meta decorator with parameters, defined in explicit functions Steven D'Aprano <steve+comp.lang.python@pearwood.info> - 2016-06-28 18:39 +1000
Re: Meta decorator with parameters, defined in explicit functions Lawrence D’Oliveiro <lawrencedo99@gmail.com> - 2016-06-29 19:43 -0700
Re: Meta decorator with parameters, defined in explicit functions Steven D'Aprano <steve@pearwood.info> - 2016-06-30 13:49 +1000
Fear and suspicion of lambdas, was Re: Meta decorator with parameters, defined in explicit functions Peter Otten <__peter__@web.de> - 2016-06-30 09:25 +0200
Re: Fear and suspicion of lambdas, was Re: Meta decorator with parameters, defined in explicit functions Lawrence D’Oliveiro <lawrencedo99@gmail.com> - 2016-06-30 00:43 -0700
Re: Fear and suspicion of lambdas, was Re: Meta decorator with parameters, defined in explicit functions Steven D'Aprano <steve+comp.lang.python@pearwood.info> - 2016-06-30 18:00 +1000
Re: Fear and suspicion of lambdas, was Re: Meta decorator with parameters, defined in explicit functions Peter Otten <__peter__@web.de> - 2016-06-30 10:41 +0200
Re: Fear and suspicion of lambdas, was Re: Meta decorator with parameters, defined in explicit functions dieter <dieter@handshake.de> - 2016-07-01 09:04 +0200
Re: Fear and suspicion of lambdas, was Re: Meta decorator with parameters, defined in explicit functions Ben Bacarisse <ben.usenet@bsb.me.uk> - 2016-07-01 21:25 +0100
Re: Fear and suspicion of lambdas, was Re: Meta decorator with parameters, defined in explicit functions Ben Finney <ben+python@benfinney.id.au> - 2016-07-02 11:52 +1000
Re: Fear and suspicion of lambdas, was Re: Meta decorator with parameters, defined in explicit functions dieter <dieter@handshake.de> - 2016-07-02 08:57 +0200
Re: Fear and suspicion of lambdas, was Re: Meta decorator with parameters, defined in explicit functions Ben Finney <ben+python@benfinney.id.au> - 2016-07-02 18:00 +1000
Re: Meta decorator with parameters, defined in explicit functions Lawrence D’Oliveiro <lawrencedo99@gmail.com> - 2016-06-29 19:50 -0700
Re: Meta decorator with parameters, defined in explicit functions Lawrence D’Oliveiro <lawrencedo99@gmail.com> - 2016-07-01 15:08 -0700
Re: Meta decorator with parameters, defined in explicit functions Ian Kelly <ian.g.kelly@gmail.com> - 2016-07-01 23:09 -0600
Re: Meta decorator with parameters, defined in explicit functions Lawrence D’Oliveiro <lawrencedo99@gmail.com> - 2016-07-01 23:40 -0700
Re: Meta decorator with parameters, defined in explicit functions Ian Kelly <ian.g.kelly@gmail.com> - 2016-07-02 22:48 -0600
Re: Meta decorator with parameters, defined in explicit functions Lawrence D’Oliveiro <lawrencedo99@gmail.com> - 2016-07-02 22:37 -0700
Re: Meta decorator with parameters, defined in explicit functions Ian Kelly <ian.g.kelly@gmail.com> - 2016-07-03 05:52 -0600
Re: Meta decorator with parameters, defined in explicit functions Lawrence D’Oliveiro <lawrencedo99@gmail.com> - 2016-07-03 14:17 -0700
Re: Meta decorator with parameters, defined in explicit functions Ian Kelly <ian.g.kelly@gmail.com> - 2016-07-03 16:38 -0600
Re: Meta decorator with parameters, defined in explicit functions Lawrence D’Oliveiro <lawrencedo99@gmail.com> - 2016-07-03 16:25 -0700
Re: Meta decorator with parameters, defined in explicit functions Chris Angelico <rosuav@gmail.com> - 2016-07-04 09:39 +1000
Re: Meta decorator with parameters, defined in explicit functions Lawrence D’Oliveiro <lawrencedo99@gmail.com> - 2016-07-03 16:59 -0700
Re: Meta decorator with parameters, defined in explicit functions Chris Angelico <rosuav@gmail.com> - 2016-07-04 10:06 +1000
Re: Meta decorator with parameters, defined in explicit functions Lawrence D’Oliveiro <lawrencedo99@gmail.com> - 2016-07-03 17:23 -0700
Re: Meta decorator with parameters, defined in explicit functions Ian Kelly <ian.g.kelly@gmail.com> - 2016-07-03 18:01 -0600
Re: Meta decorator with parameters, defined in explicit functions Lawrence D’Oliveiro <lawrencedo99@gmail.com> - 2016-07-03 17:06 -0700
Re: Meta decorator with parameters, defined in explicit functions Ian Kelly <ian.g.kelly@gmail.com> - 2016-07-03 18:20 -0600
Re: Meta decorator with parameters, defined in explicit functions Ben Finney <ben+python@benfinney.id.au> - 2016-07-02 15:32 +1000
Re: Meta decorator with parameters, defined in explicit functions Ian Kelly <ian.g.kelly@gmail.com> - 2016-07-01 23:53 -0600
Page 2 of 2 — ← Prev page 1 [2]
| From | Ian Kelly <ian.g.kelly@gmail.com> |
|---|---|
| Date | 2016-07-03 05:52 -0600 |
| Message-ID | <mailman.38.1467546815.2295.python-list@python.org> |
| In reply to | #110976 |
On Sat, Jul 2, 2016 at 11:37 PM, Lawrence D’Oliveiro <lawrencedo99@gmail.com> wrote: > On Sunday, July 3, 2016 at 4:49:15 PM UTC+12, Ian wrote: >> >> On Sat, Jul 2, 2016 at 12:40 AM, Lawrence D’Oliveiro wrote: >>> >>> On Saturday, July 2, 2016 at 5:10:06 PM UTC+12, Ian wrote: >>>> >>>> You should use functools.wraps instead of clobbering the decorated >>>> function's name and docstring: >>> >>> Where am I doing that? >> >> Using the implementation you posted: >> >>>>> @decorator_with_args >> ... def my_decorator(func, *args, **kwargs): >> ... """Returns func unmodified.""" >> ... return func >> ... >>>>> my_decorator.__doc__ >> 'generates a decorator which applies my_decorator to the given arguments' > > That is a function that I am generating, so naturally I want to give it a useful docstring. Am I “clobbering” any objects passed in by the caller, or returned by the caller? No, I am not. It isn't useful, though. If somebody writes a docstring for a function, it's because they want that to be the docstring for the function, not some arbitrary and vague docstring assigned by a decorator. If I type "help(my_decorator)" in the interactive interpreter, I should see what my_decorator actually does, not "generates a decorator which applies my_decorator", which just confuses with its recursiveness. The only way to find out what my_decorator actually does from the interactive interpreter would be to realize that it's been opaquely decorated and type out something like this: >>> my_decorator.__closure__[0].cell_contents.__doc__ 'Returns func unmodified.' That's far too obscure. Alternatively, one could go read the source. But if you have to go read the source to understand what a function does, then you've lost the purpose of having a docstring in the first place.
[toc] | [prev] | [next] | [standalone]
| From | Lawrence D’Oliveiro <lawrencedo99@gmail.com> |
|---|---|
| Date | 2016-07-03 14:17 -0700 |
| Message-ID | <d2f71d72-d2da-4f68-9d6a-ca059327afdd@googlegroups.com> |
| In reply to | #110992 |
On Sunday, July 3, 2016 at 11:53:46 PM UTC+12, Ian wrote: > On Sat, Jul 2, 2016 at 11:37 PM, Lawrence D’Oliveiro wrote: >> That is a function that I am generating, so naturally I want to give it a >> useful docstring. Am I “clobbering” any objects passed in by the caller, >> or returned by the caller? No, I am not. > > It isn't useful, though. If somebody writes a docstring for a > function, it's because they want that to be the docstring for the > function ... Which I am not “clobbering” at all. Do you get that yet? My docstrings apply to *my* functions, not those supplied or generated by the caller.
[toc] | [prev] | [next] | [standalone]
| From | Ian Kelly <ian.g.kelly@gmail.com> |
|---|---|
| Date | 2016-07-03 16:38 -0600 |
| Message-ID | <mailman.47.1467585556.2295.python-list@python.org> |
| In reply to | #111010 |
On Sun, Jul 3, 2016 at 3:17 PM, Lawrence D’Oliveiro <lawrencedo99@gmail.com> wrote: > On Sunday, July 3, 2016 at 11:53:46 PM UTC+12, Ian wrote: >> On Sat, Jul 2, 2016 at 11:37 PM, Lawrence D’Oliveiro wrote: >>> That is a function that I am generating, so naturally I want to give it a >>> useful docstring. Am I “clobbering” any objects passed in by the caller, >>> or returned by the caller? No, I am not. >> >> It isn't useful, though. If somebody writes a docstring for a >> function, it's because they want that to be the docstring for the >> function ... > > Which I am not “clobbering” at all. Do you get that yet? My docstrings apply to *my* functions, not those supplied or generated by the caller. Sorry, but you're the one who doesn't seem to get it. Because it's a decorator, "your" function is replacing the caller's function in the caller's namespace. If the docstring written in the code for function m.f is x, but the value of m.f.__doc__ is actually y, then the docstring x is, for all practical purposes, clobbered. That you're not actually modifying the original function is irrelevant. For the purpose of the built-in help, it's the value of m.f.__doc__ that counts. For the purpose of documentation built with pydoc, it's the value of m.f.__doc__ that counts. If the documentation for every decorator in a module just reads "generates a decorator which applies <function name> to the given arguments", that's useless documentation. Which brings me to the other half of the point I was trying to make: your decorator_with_args doesn't even *need* a docstring. It's not part of the public interface. As a nested function that doesn't have its own name within the module, help() or pydoc won't even include it in their output. If you want to put something in the code to explain what it does, that's fine, but use a comment for that. The docstring doesn't add any value.
[toc] | [prev] | [next] | [standalone]
| From | Lawrence D’Oliveiro <lawrencedo99@gmail.com> |
|---|---|
| Date | 2016-07-03 16:25 -0700 |
| Message-ID | <62b43f29-e6ea-4d19-9e9f-1becb3988bd3@googlegroups.com> |
| In reply to | #111016 |
On Monday, July 4, 2016 at 10:39:30 AM UTC+12, Ian wrote:
> Sorry, but you're the one who doesn't seem to get it. Because it's a
> decorator, "your" function is replacing the caller's function in the
> caller's namespace.
No it is not. The replacement happens here:
def generated_decorator(func) :
return \
decorator(func, *args, **kwargs)
#end generated_decorator
As you can see, the function being called, “decorator”, is supplied by the caller. The function being decorated, “func”, is supplied by the caller (along with the additional *args and **kwargs). And the returned function is returned *as-is*, so whatever docstring was assigned by the caller is *NOT* “clobbered”.
Once again, the only docstrings I am setting are the ones for functions that *I* generate.
Do you understand that yet?
[toc] | [prev] | [next] | [standalone]
| From | Chris Angelico <rosuav@gmail.com> |
|---|---|
| Date | 2016-07-04 09:39 +1000 |
| Message-ID | <mailman.49.1467589185.2295.python-list@python.org> |
| In reply to | #111019 |
On Mon, Jul 4, 2016 at 9:25 AM, Lawrence D’Oliveiro
<lawrencedo99@gmail.com> wrote:
> On Monday, July 4, 2016 at 10:39:30 AM UTC+12, Ian wrote:
>> Sorry, but you're the one who doesn't seem to get it. Because it's a
>> decorator, "your" function is replacing the caller's function in the
>> caller's namespace.
>
> No it is not. The replacement happens here:
>
> def generated_decorator(func) :
> return \
> decorator(func, *args, **kwargs)
> #end generated_decorator
>
> As you can see, the function being called, “decorator”, is supplied by the caller. The function being decorated, “func”, is supplied by the caller (along with the additional *args and **kwargs). And the returned function is returned *as-is*, so whatever docstring was assigned by the caller is *NOT* “clobbered”.
>
> Once again, the only docstrings I am setting are the ones for functions that *I* generate.
>
> Do you understand that yet?
Yes, in a technical sense, you are correct. It's also technically
correct to say that str.upper() doesn't convert its argument to
uppercase - it constructs a completely new string of all uppercase
letters. But in normal usage, people expect "x = x.upper()" to return
*the same string, uppercased*. In the same way, people expect "f =
deco(f)" to return *the same function, decorated*. Technically it's
generally going to be a new function, because functions are immutable
(more-or-less), but it should broadly be the same function.
def require_login(f):
def modified(*a, **kw):
if not logged_in:
return "You must be logged in to do this."
return f(*a, **kw)
return modified
@require_login
def fire_ze_missiles():
raise Exhausted
@require_login
def reboot_server(server):
"""Reboot the specified server"""
server.send_command("sudo reboot")
Tell me, should the docstring for reboot_server be "Reboot the
specified server", or not? If not, why not?
ChrisA
[toc] | [prev] | [next] | [standalone]
| From | Lawrence D’Oliveiro <lawrencedo99@gmail.com> |
|---|---|
| Date | 2016-07-03 16:59 -0700 |
| Message-ID | <0b85cc58-0552-41b3-8729-0f037e33c183@googlegroups.com> |
| In reply to | #111020 |
On Monday, July 4, 2016 at 11:39:56 AM UTC+12, Chris Angelico wrote:
> In the same way, people expect "f = deco(f)" to return *the same function,
> decorated*.
I am not changing that in anyway. The decorated function generated by the caller is returned *unchanged*.
Once again, the only docstrings I am setting are for the intermediate functions *I* generate.
Suppose we have the following:
def try_func(func, arg) :
"sample function to be turned into a decorator."
def result() :
"returns func unchanged."
return \
func()
#end result
#begin try_func
result.__name__ = func.__name__
result.__doc__ = func.__doc__
return \
result
#end try_func
then:
>>> f = decorator_with_args(try_func)
>>> help(f)
Help on function decorate_with_try_func in module decorator_try:
decorate_with_try_func(*args, **kwargs)
generates a decorator which applies try_func to the given arguments
>>> @f(None)
... def g() :
... "my docstring--should be unchanged."
... return \
... 1
... #end g
...
>>> help(g)
Help on function g in module decorator_try:
g()
my docstring--should be unchanged.
Do you understand now?
[toc] | [prev] | [next] | [standalone]
| From | Chris Angelico <rosuav@gmail.com> |
|---|---|
| Date | 2016-07-04 10:06 +1000 |
| Message-ID | <mailman.53.1467590768.2295.python-list@python.org> |
| In reply to | #111022 |
On Mon, Jul 4, 2016 at 9:59 AM, Lawrence D’Oliveiro <lawrencedo99@gmail.com> wrote: > #begin try_func > result.__name__ = func.__name__ > result.__doc__ = func.__doc__ > return \ > result > #end try_func This is the bit we're talking about. You're doing manually what functools.wraps does for you (and it does other stuff too, to make help() more useful), and you weren't doing this before. Your original docstring on result() is completely ignored. ChrisA
[toc] | [prev] | [next] | [standalone]
| From | Lawrence D’Oliveiro <lawrencedo99@gmail.com> |
|---|---|
| Date | 2016-07-03 17:23 -0700 |
| Message-ID | <d7bbef93-ccc8-4ebc-b025-98a70fe64197@googlegroups.com> |
| In reply to | #111026 |
On Monday, July 4, 2016 at 12:06:21 PM UTC+12, Chris Angelico wrote: > On Mon, Jul 4, 2016 at 9:59 AM, Lawrence D’Oliveiro wrote: >> #begin try_func >> result.__name__ = func.__name__ >> result.__doc__ = func.__doc__ >> return \ >> result >> #end try_func > > This is the bit we're talking about. This isn’t part of my decoration mechanism, this is just an example of it in use.
[toc] | [prev] | [next] | [standalone]
| From | Ian Kelly <ian.g.kelly@gmail.com> |
|---|---|
| Date | 2016-07-03 18:01 -0600 |
| Message-ID | <mailman.52.1467590530.2295.python-list@python.org> |
| In reply to | #111019 |
On Sun, Jul 3, 2016 at 5:25 PM, Lawrence D’Oliveiro <lawrencedo99@gmail.com> wrote: > On Monday, July 4, 2016 at 10:39:30 AM UTC+12, Ian wrote: >> Sorry, but you're the one who doesn't seem to get it. Because it's a >> decorator, "your" function is replacing the caller's function in the >> caller's namespace. > > No it is not. The replacement happens here: > > def generated_decorator(func) : > return \ > decorator(func, *args, **kwargs) > #end generated_decorator > > As you can see, the function being called, “decorator”, is supplied by the caller. The function being decorated, “func”, is supplied by the caller (along with the additional *args and **kwargs). And the returned function is returned *as-is*, so whatever docstring was assigned by the caller is *NOT* “clobbered”. I'm talking about the docstring of the *decorator*, not func. I agree that whatever docstring func has is entirely up to func and the decorator, not your code. Here again is the example I posted earlier: >>> @decorator_with_args ... def my_decorator(func, *args, **kwargs): ... """Returns func unmodified.""" ... return func ... >>> my_decorator.__doc__ 'generates a decorator which applies my_decorator to the given arguments' I never made any claim about the docstring of the decorated func.
[toc] | [prev] | [next] | [standalone]
| From | Lawrence D’Oliveiro <lawrencedo99@gmail.com> |
|---|---|
| Date | 2016-07-03 17:06 -0700 |
| Message-ID | <19025b2c-ba2e-4683-af50-ff208d1e9a49@googlegroups.com> |
| In reply to | #111025 |
On Monday, July 4, 2016 at 12:02:23 PM UTC+12, Ian wrote: > I'm talking about the docstring of the *decorator*, not func. *Sigh*. Originally somebody was complaining that the lambda version didn’t allow for good (or any) docstrings. So I posted my version, and I went to all the effort of ensuring that every generated function had a good docstring. And now you are trying to knock me down for that? What the hell is wrong with you people?!?
[toc] | [prev] | [next] | [standalone]
| From | Ian Kelly <ian.g.kelly@gmail.com> |
|---|---|
| Date | 2016-07-03 18:20 -0600 |
| Message-ID | <mailman.54.1467591655.2295.python-list@python.org> |
| In reply to | #111027 |
On Sun, Jul 3, 2016 at 6:06 PM, Lawrence D’Oliveiro <lawrencedo99@gmail.com> wrote: > On Monday, July 4, 2016 at 12:02:23 PM UTC+12, Ian wrote: >> I'm talking about the docstring of the *decorator*, not func. > > *Sigh*. Originally somebody was complaining that the lambda version didn’t allow for good (or any) docstrings. So I posted my version, and I went to all the effort of ensuring that every generated function had a good docstring. And now you are trying to knock me down for that? > > What the hell is wrong with you people?!? Sorry. I don't know who that was or what they wrote, because your post is the first mention of docstrings that I see in this thread. Maybe you're thinking of some other thread. I don't read more than a fraction of what gets posted to this list. But I read your post and I saw a way to improve the code in it, so I suggested it. Next time I won't bother.
[toc] | [prev] | [next] | [standalone]
| From | Ben Finney <ben+python@benfinney.id.au> |
|---|---|
| Date | 2016-07-02 15:32 +1000 |
| Message-ID | <mailman.16.1467437546.2295.python-list@python.org> |
| In reply to | #110921 |
Ian Kelly <ian.g.kelly@gmail.com> writes: > You should use functools.wraps instead of clobbering the decorated > function's name and docstring: > > @functools.wraps(decorator) > def decorate(*args, **kwargs): > ... Thanks. Can you write the full implementation with that, so I can be sure of where you expect that to go? -- \ “I knew things were changing when my Fraternity Brothers threw | `\ a guy out of the house for mocking me because I'm gay.” | _o__) —postsecret.com, 2010-01-19 | Ben Finney
[toc] | [prev] | [next] | [standalone]
| From | Ian Kelly <ian.g.kelly@gmail.com> |
|---|---|
| Date | 2016-07-01 23:53 -0600 |
| Message-ID | <mailman.17.1467438837.2295.python-list@python.org> |
| In reply to | #110921 |
On Fri, Jul 1, 2016 at 11:32 PM, Ben Finney <ben+python@benfinney.id.au> wrote:
> Ian Kelly <ian.g.kelly@gmail.com> writes:
>
>> You should use functools.wraps instead of clobbering the decorated
>> function's name and docstring:
>>
>> @functools.wraps(decorator)
>> def decorate(*args, **kwargs):
>> ...
>
> Thanks. Can you write the full implementation with that, so I can be
> sure of where you expect that to go?
def decorator_with_args(decorator):
"""Given function decorator(func, *args, **kwargs), returns a
wrapper that accepts args and kwargs separately from func.
"""
@functools.wraps(decorator)
def apply(*args, **kwargs):
# inner_decorator is transient, so its name and docstring
# are unimportant.
def inner_decorator(func):
return decorator(func, *args, **kwargs)
return inner_decorator
return apply
[toc] | [prev] | [standalone]
Page 2 of 2 — ← Prev page 1 [2]
Back to top | Article view | comp.lang.python
csiph-web