Once again, lobste.rs comments have helped make my writing better. Starting to be tempted to post thing first here, wait for comments, update appropriately, and only then post elsewhere.
Thanks for correction!. I wonder why I didn’t catch that when writing the post, I was using Python 3.5. Probably screwed up reloading the code or something. Will update post after dinner.
The point, which I will try to make more explicit, is that decorators are a wasted opportunity: it could’ve done the right thing in the language level, but instead it forces library code to fix the edge cases the language doesn’t handle for you.
I can see two reasons why the current behavior is preferable:
Explicit is better than implicit. If it automatically switched the docstring, it would make decorations have a different behavior from manually wrapping a function, which adds magic.
What would be the expected behavior for functions that return decorators? For example, you don’t write @lru_cache, you write @lru_cache().
Edit: another case is if you explicitly want to do something with the docstring, like make a depreciated decorator. This would be a lot harder if decorators automatically used the wrapped functions attributes.
It’s not like @something is particularly explicit. It’s a language feature that does a thing, seems reasonable that it would do some other things too.
Not sure that’s relevant? In the end you’re returning a function, and that is what gets mutated.
Could’ve been solved with different syntax. Current syntax is not ideal. The decorator factory case always confuses me :)
More broadly: decorators were added in 2.4. functools.wraps was added in 2.6. So fundamentally the use case of callers wasn’t addressed by Python all until then.
I’ve updated this based on @KevinMGranger and @hwayne’s comments.
Once again, lobste.rs comments have helped make my writing better. Starting to be tempted to post thing first here, wait for comments, update appropriately, and only then post elsewhere.
The complaint about the signature was fixed in python3.4.
Thanks for correction!. I wonder why I didn’t catch that when writing the post, I was using Python 3.5. Probably screwed up reloading the code or something. Will update post after dinner.
add = synchronized(add)doesn’t preserve the docstring either, so at worst decorators are API-neutral.The point, which I will try to make more explicit, is that decorators are a wasted opportunity: it could’ve done the right thing in the language level, but instead it forces library code to fix the edge cases the language doesn’t handle for you.
I can see two reasons why the current behavior is preferable:
@lru_cache, you write@lru_cache().Edit: another case is if you explicitly want to do something with the docstring, like make a depreciated decorator. This would be a lot harder if decorators automatically used the wrapped functions attributes.
Responding respectively:
@somethingis particularly explicit. It’s a language feature that does a thing, seems reasonable that it would do some other things too.More broadly: decorators were added in 2.4.
functools.wrapswas added in 2.6. So fundamentally the use case of callers wasn’t addressed by Python all until then.