[omaha] Decorators

Chris Calloway cbc at unc.edu
Tue Jan 15 16:41:58 CET 2008


Eli Criffield wrote:
>> Decorators in python are syntactic sugar to let you wrap a
>> function/method with another function.

Hey guys, two things.

1) This article about decorators is what you need to know, is 
comprehensive, and is the most digestible thing about decorators out there:

http://www.ddj.com/184406073

The Python documentation about decorators should be as good as that 
article. And the fact that it's not says, um, several things I don't 
want to go into.

Also, here's another very respectable article, if you already understand 
the previous one (and a good bit about metaclasses):

http://www.ibm.com/developerworks/linux/library/l-cpdecor.html

(The good Dr. Mertz might be the best writer about Python out there.)

2) You don't need the third party decorator module. It just pulls in 
some predefined decorators that some people have found useful like 
memoize, locked, delayed, threaded, and blocking. Plus it adds a 
decorator which is confusingly called "decorator," and which you *can* 
use to create decorators of a particular convention that *may* 
occasionally be useful (if using a factory-factory could ever be useful).

Most people who use decorators already have their own utility module of 
useful decorators.

The thing about decorators is they get used a lot by decorator-happy 
people who just learned about them or are trying to be overly clever. 
They are seldom all that useful. They have their place. There are some 
pretty standard decorators like memoize that many people understand 
already without having to look at what they do or how they do it.

But often decorator usage is a bit overblown. Anything more than the 
simplest decorators add unnecessary and unreadable complexity to you 
code. And you don't want that. It isn't pythonic to add unnecessary and 
unreadable complexity to you code. The idea is to quickly write useful, 
testable, tested, sharable, and maintainable code; not to prove what an 
awesome computer scientist you are. :)

You have to invest a lot to properly understand and use decorators. And 
then they get only a little and often trivial usage (do we really need 
an "author" attribute added to all of our functions; and if so, do we 
really need a decorator to do that?). Most of the time, decorators 
aren't worth it.

Decorators are most useful for dorking around with metaclasses, which is 
another high investment/low return pattern. They're something you need 
to know to understand other people's code sometimes. If you find 
yourself using them a lot, you need to look  in the mirror and ask 
yourself if you've really got a good overriding reason. Decorators tend 
to add "magic" at the cost of readability.

They can also be seriously misused because using them requires 
remembering and following some recommendations that are not enforced by 
Python. The third party decorator module's "decorator" decorator is 
supposed to help with that somewhat. But then, if you need help with 
that, you probably shouldn't be using them.

Certain levels of abstraction come at a steep cost. If understanding the 
abstraction is more difficult than understanding what is being 
abstracted, some soul searching is in order.

Apparently, decorators had to be added to Python because Java had them. Oof.

Notice that even though decorators are officially part of Python syntax, 
the official Python tutorial doesn't mention them. Anywhere. The fact 
is, if you know and need the decorator *programming pattern* (and the 
need and the knowledge should come before throwing around the syntax), 
then you don't even need the syntatic sugar that Python provides to use 
them. There were two built-in decorators (classmethod and staticmethod) 
already available in Python 2.2 before the decorator syntax was even 
added in Python 2.4.

It's just passing a callable to a callable which returns a callable 
which is then assigned to the original callable's identifier. Like this:

a = b(a)

where "a" is callable as well as b. The callable "b" just "decorates" 
the callable "a" with, um, something. Like maybe a new attribute.

The decorator syntax just moves the order of reading the code around by 
showing "b" will decorate "a" after "a" is defined:

@b
def a(some, arguments, maybe):
     # a's body goes here

It'd kind of like saying, "Here's an ornament which will go on the tree 
I'm about to put up," and then saying, "Here's the tree!," instead of 
saying, "Here's the tree, now let's decorate it with these ornaments." 
Six of one...

-- 
Sincerely,

Chris Calloway
http://www.seacoos.org
office: 332 Chapman Hall   phone: (919) 962-4323
mail: Campus Box #3300, UNC-CH, Chapel Hill, NC 27599






More information about the Omaha mailing list