[Python-ideas] Bad programming style in decorators?

u8y7541 The Awesome Person surya.subbarao1 at gmail.com
Mon Jan 4 19:04:06 EST 2016


Yes, I knew this already. This is what I understood when I said I
understood. I thought the *decorator* had a function inside it, not
the *decorator
factory*. So of course the decorator factory is only called twice.

On Mon, Jan 4, 2016 at 10:48 AM, Andrew Barnert <abarnert at yahoo.com> wrote:

> (off-list, because I think this is no longer relevant to suggesting
> changes to Python)
>
> On Sunday, January 3, 2016 10:58 AM, u8y7541 The Awesome Person <
> surya.subbarao1 at gmail.com> wrote:
>
>
>
> >Thanks for explaining the differences tho. I got confused between the
> decorator and the decorator factory, thinking the decorator had a function
> inside it. Sorry :)
>
> I think you're _still_ confused. Not your fault, because this is confusing
> stuff. The decorator actually does (usually) have a function definition in
> it too. But the decorated function--the wrapper that it defines--doesn't.
> And that's the thing that you usually call a zillion times, not the
> decorator or the decorator factory.
>
> Let's make it concrete and as simple as possible, and then walk through
> all the details:
>
>
>     def div(id):
>         def decorator(func):
>
>             @wraps(func)
>             def wrapper(*args, **kw):
>                 return "<div id='{}'>{}</div>".format(id, func(*args,
> **kw))
>             return wrapper
>         return decorator
>
>     @div('eggs')
>     def eggs():
>         return 'eggs'
>
>     @div('cheese')
>     def cheeses():
>         return '<ul><li>gouda</li><li>edam</li></ul>'
>
>     for _ in range(1000000):
>         print(eggs())
>         print(cheeses())
>
> When you're importing the module and hit that "@div('eggs')", that calls
> the "div" factory. The only other time that happens is at the
> "@div('cheese')". So, the factory does of course create a function, but the
> factory only gets called twice in your entire program. (Also, the functions
> it creates become garbage as soon as they're called, so by the time you get
> to the "for" loop, they've both been deleted.)
>
> When you finish the "def eggs():" or "def cheeses():" statement, the
> decorator function "decorator" returned by "div('eggs')" or "div('cheese')"
> gets called. And that decorator also creates a function. But each one only
> gets called once in your entire program, and there are only two of them, so
> that's only two extra function definitions. (Obviously these two aren't
> garbage--they're the functions you call inside the loop.)
>
> When you hit that "print(eggs())" line, you're calling the decorated
> function "wrapper", returned by the decorator function "decorator",
> returned by the decorator factory function "div". That function does not
> have a function definition inside of it. So, calling it a million times
> doesn't cost anything in function definitions.
>
> And of course "div" itself isn't garbage--you don't need it anymore, but
> if you don't tell Python "del div", it'll stick around. So, at your peak,
> in the middle of that "for" loop, you have 5 function definitions around
> (div, decorated eggs, original eggs, decorated cheese, original cheese).
>
> If you refactor things differently, you could have 5 functions, 2 class
> objects, 2 class instances (your intended class-style design); or 4
> functions, 1 class object, 2 class instances, 2 bound methods, (a simple
> class-style decorator); 4 functions, 1 class object, 2 class instances,
> (the smallest possible class-style decorator); 2 functions but with
> duplicated code and string constants (by inlining div directly into each
> function); or 3 functions (with eggs and cheese explicitly calling div--I
> suspect this would be actually be smallest here); etc. The difference is
> going to be a few hundred bytes one way or the other, and the smallest
> possible design may have a severe cost in (time) performance or in
> readability. But, as you suggested, and Nick confirmed, there are cases
> where it matters. Which means it's worth knowing how to write all the
> different possibilities, and evaluate them analytically, and test them.
>



-- 
-Surya Subbarao
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/python-ideas/attachments/20160104/c8e13bb9/attachment.html>


More information about the Python-ideas mailing list