On Wed, Jul 06, 2016 at 03:35:16PM -0400, bruce wrote: > Hi. > > Saw the decorator thread earlier.. didn't want to pollute it. I know, > I could google! > > But, what are decorators, why are decorators? who decided you needed > them!
Sometimes you find yourself writing many functions (or methods) that have bits in common. For example, you might have a bunch of mathematical functions that all start off with the same boring code "check that the argument x is a number, raise an exception if it isn't". Sure, it's only two or three lines, but if you've got twenty functions to write, you have to write those same lines twenty times. And then if you decide to change the error message, or change the way you check something is a number, you have to do that in twenty places. A decorator let's you factor out that common code into a single place, so you only need to make changes to *one* place instead of twenty separate functions. You still have to apply the decorator to each of the functions, but that's only once line. Besides, a decorator is not really about cutting back the number of lines of code (although it is nice when that happens) as it is about moving common code to one place. def verify_numeric_argument(func): """Decorator that checks the argument to a function is a number.""" @functools.wraps(func) def inner(x): if isinstance(x, numbers.Number): return func(x) else: kind = type(x).__name__ raise TypeError("expected a number, but got %s" % kind) return inner @verify_numeric_argument def sinc(x): if x == 0: return 1.0 else: return math.sin(x)/x Obviously you wouldn't bother if you're only going to do it *once*. There's a bunch of overhead involved in writing a decorator, usually about five or six lines of code per decorator. The rule of thumb I use is that if I have one or two functions with the same, common, chunk of code, I probably wouldn't bother; if I have three functions, I might, and if I have four or more, then I probably will. But as I said, it's not really about saving lines of code. It's about keeping code that belongs together in one place, and about recognising when functions repeat the same structure. If you have a bunch of functions that look like this: def function(arguments): boring boilerplate that is the same each time interesting bit that is different each time more boring boilingplate return result then this is a great candidate for a decorator: move the boring boilerplate into the decorator, then turn the functions into this: @apply_boilerplate def function(arguments): interesting bit that is different each time return result Doesn't that look better? That's the purpose of the decorator: move the boring bits, or sometimes the hard, complicated bits, away so you can focus on the interesting bits. Depending on just how boring that boilerplate is, I might even do it for ONE function, just to get it out of the way. -- Steve _______________________________________________ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor