
Painless Decorators in Python - Suor
http://hackflow.com/blog/2013/11/03/painless-decorators/
======
Goopplesoft
>to reduce clutter and expose your intentions. However, there is usual cost.
This as any abstraction brings an additional layer of complexity on top of
python. And python could be seen as a layer on top of c, and that as one above
asm, and that

I took a look at the rest of funcy and it seems a great package, thanks!
However, a python dev I'm expected to know how decorators work not how funcy
makes decorators work. So unless this was part of the standard lib most devs
who already know how decorators work would end up having to read another doc.
I dont think its an issue of abstraction (the code is straight forward python:
[https://github.com/Suor/funcy/blob/master/funcy/decorators.p...](https://github.com/Suor/funcy/blob/master/funcy/decorators.py)
) but rather uniformity. I think coping with the standard library until
something like this becomes part of it is the best strategy.

~~~
unoti
This is a matter of taste. I think certain standard abstractions in Python are
pretty terrible, and really need to be upgraded. The standard way of doing
function decoration isn't good. Neither is the standard way of accessing
mysql. These, and a number of other things, really should have better
abstractions built on them to amplify productivity and readability.

Sometimes there's a war between standard techniques and DRY principles. I've
observed a lot of good coming from adhering to the idea of never copying code
or doing boilerplate. But as you point out, sometimes it can lead to a bunch
of nonstandard code. But I think any non-trivial codebase is going to have a
chunk of abstractions it creates and builds upon to amplify its own
expressiveness. When you can import some of those abstractions, that's
arguably a win. There are lots of people that would (and have) disagreed with
me on this point, but it is a subjective matter of taste.

------
j1z0
The article is interesting but really if you want to make decorators easier to
understand don't introduce another layer of abstraction, use a class. The
__init__ function handles the decorator arguments just like you would expect
from a class. The __call__ function is called when the decorator is called,
just return your new function and well; your done. And it's all pretty
straight forward.

~~~
Suor
You will still need a wrapper function and update it's metadata. Which is even
more boilerplate. Or you can hide that in base Decorator class, but then we'll
back to another layer of abstraction.

So it's either more boilerplate or more abstraction. Choose exactly one.

~~~
j1z0
Well if you use functools like you started with in your lead up examples your
talking about what two lines of boilerplate (functools decorator and function
definition)? Personally I often times just add the four lines of boiler plate
and forgo functools.... Look I'm not saying that your library is a bad idea;
Its neat, in fact it seems to handle a few thing better than the more well
known decorator library does.

( Out of curiosity though how about the functions signature, I think functools
doesn't maintain the original functions signature but I think decorator does,
what does funcy do? )

For me personally I feel its better to have the decorator all in one place
where you can see everything that is going on, and making it a class makes it
pretty straight forward to understand.

~~~
Suor
funcy doesn't preserve function signature. The only way for now to do this is
to use exec, e.g. compile code from source or AST, which I choose to avoid.

------
Leszek
How does this compare to the decorator module?

[https://pypi.python.org/pypi/decorator](https://pypi.python.org/pypi/decorator)

~~~
Suor
This handles decorators with arguments and makes a general case of passing
same arguments to function as to wrapper less cluttered.

~~~
abecedarius
It might help to show the same examples from that module's documentation, how
they are similar or different.

I still don't understand this after a skim of your post, since one example has

    
    
        @decorator
        def some_decorator(func, args, kwargs):
    

while the next goes

    
    
        @decorator
        def some_decorator(call):
    

Does this introspect on the parameters of some_decorator?

FWIW I'm happy enough with
[https://github.com/darius/sketchbook/blob/master/misc/decora...](https://github.com/darius/sketchbook/blob/master/misc/decorator.py)

~~~
Suor
The first part of a post is mere reasoning showing how I got to the actual
interface I use. @decorator works with `call` not with `func, _args,_
*kwargs`.

~~~
abecedarius
Ah, OK. So there's no way to express an example that needs to get at func,
etc.?

I think I'd separate out an @decorator that fixes the metadata on the returned
function, and another one, using it, that makes a decorator that works on the
call() interface.

------
anfedorov
Great library! I wrote something similar once [1] and thought two special
cases might be useful to optimize for: a predecoration that modifies the
arguments to a function and a postdecoration that modifies the return value.

1\.
[https://github.com/anfedorov/decorations](https://github.com/anfedorov/decorations)

------
JeffJenkins
It's important when adding a layer of abstraction like this to consider both
how much it makes this simpler, but also how much you're going to use it.
While it makes some common decorator patterns easier, your code really
shouldn't have so many decorators that having to understand this library is
made up for in the number of places it simplifies the code.

If I'm writing code and using a lot of _different_ decorators everywhere I
take that as a sign that something is probably wrong.

------
Qantourisc
You might want to look into class-based decorators, they take some of the pain
away.

~~~
Suor
This looks like even more boilerplate.

~~~
ekimekim
Arguably, it can make things easier to read in cases where you want "static"
variables, eg. a decorator that synchronises a function with a lock. The lock
shouldn't be passed in by the user, nor should it be created in an individual
invocation of the decorated function, so having a class to contain the state
is useful.

~~~
jessaustin
That's a great situation in which to use a class: state you don't want to pass
in every time it's used. It doesn't seem to connect to the idea of a
decorator, though. Rather than decorating the function, why not just make it a
method of the state-managing class? Or if it shouldn't be so closely coupled,
why not just pass it the result of invoking a different method of the class?

I don't imply that there _isn 't_ a good example of a decorator that should be
a class. I just don't think we've seen one on this thread yet.

------
tehwalrus
I like this, will try it next time I need a decorator.

------
benwr
What about iterators/yield?

------
huangbop


