Closures, Partials And Decorators
Solution 1:
I think you're confusing purpose with implementation. Creating a closure is a technique for doing things. You can do a bunch of things with closures.
On the other hand, partial
and decorator
are particular purposes. Maybe they use closures. Maybe they don't. That's an implementation detail, and you don't need to worry about it. What's important is that they achieve the result you want.
Consider a partial
. (Ignoring **kwargs.) One way to create it would be to use a closure:
defpartial(f, *args):
defpf(*rest):
return f(*args, *rest)
return pf
But it doesn't have to be that way. For example:
classPartial:def__init__(self, func, args):
self.args = args
self.func = func
def__call__(self, *rest):
f = self.func
args = self.args
return f(*args, *rest)
defpartial(f, *args):
return Partial(f, args)
There's no closure here, just a variable that holds a reference to the other variables. But I get the partial behavior, so who cares?
The same is true for decorators. A decorator might be a closure, or it might not. For example, one recent question involved running str.format
on a function's __doc__
strings. That was just a case of accepting a function object, modifying the __doc__
attribute, and returning the same object. Clearly, there's no closure involved in that.
Solution 2:
Short answer: closure is the mechanism, while functools.partial
and decorators are typical uses of that mechanism.
The key difference between a closure and more typical namespaces is that the names and values in the "closed-over" namespace don't vanish when control flow leaves the top-level function. They're preserved in a mini-namespace associated with one instance of the inner function, and which survives as long as that instance does.
functools.partial
uses that ability to "remember" some arguments to a pre-existing function. Decorators also typically use that ability for the same reasons.
Note that a decorator is more flexible than that. Any callable that takes one parameter and returns something can serve as a decorator. It doesn't have to make use of Python closures, or even return a function. Many decorators return a callable object instead. (As an aside, a closure and inner function can be simulated using an object for the namespace and a method for the inner function.)
Whatever the decorator returns is assigned to the name the decorated function would have had. (Decorators with parentheses after them, like @decorator('args') ...
are slightly more complicated.) The typical decorator syntax:
@decoratordeffunction():
pass
...is just a shorthand for "define, then decorate and reassign":
def function():
pass
function = decorator(function)
For an extreme (and mostly useless) example:
defdecorator5(__):
return5@decorator5defsquare(x):
return x * x
print(square) # Prints 5 --- the function is gone.
square(10) # TypeError: 'int' object is not callable
Solution 3:
The partial version of your decorator would actually be:
defadd_nums(one):
defadder(one, two):
return one + two
return partial(adder, one)
Note that the nested function now only uses explicit parameters, not the closure. You can implement a decorator, which is just a function that takes a function and returns a (usually different) function, using either closures, partial
(which is implemented using a closure) or a mix of the two.
Post a Comment for "Closures, Partials And Decorators"