3 ms·
I don't care for that explanation, because they don't have to call the original function. (E.g. an @skip('not yet implemented') test decorator.) Or they could c
by philh 11y ago
I don't care for that explanation, because they don't have to call the original function. (E.g. an @skip('not yet implemented') test decorator.) Or they could call it multiple times. The post-decoration function doesn't even need to be a function[1]. And that doesn't touch on decorated classes, either.
I find them easiest to understand using the source-rewriting explanation:
@foo
def bar(...):
...
is the same as
def bar(...):
...
bar = foo(bar)
Classes can be decorated in the same way. This also explains why decorators taking arguments work how they do: because
@foo(...)
turns into
bar = foo(...)(bar)
and thus foo needs to return a decorator, not be a decorator. (Where a decorator can be thought of as "any function that accepts a single argument", or as "any function which happens to be useful as a decorator", or whatever.)
But explaining them like this doesn't make it obvious what they're for. (I can worry about that later, but others find it easier to understand things given a motivating example.) And some people haven't got their heads around first-class functions yet. So while this would be my preferred explanation if I was talking to a version of me who didn't know decorators yet, it's not the best for everyone.
[1] This hasn't previously occurred to me, and I've never seen it explored, but I just verified that it works:
def const(fun):
return fun()
@const
def bar():
return 3
print 3 * bar # 9
I'm not sure if this would be useful for anything.