I have a piece of code I pulled from someone I don't understand:
def __init__(self, func):
self.func = func
wraps(func)(self)
I've seen things like wraps(func)(self)
several times but never seen it explained. How is there a function with parameters and then another (var)
thing after it? What does it all mean? Thank you
Functions are first-class objects in Python.
You have no doubt encountered this on the command line if you have typed the name only of a function without parentheses.
In [2]: a
Out[2]: <function __main__.a>
When you see a(b)(c)
it is a method of chaining:
a
is defined to return another function.a(b)
calls a
and returns that reference (to a callable function)a(b)(c)
calls whatever function was returned by a
with c
as an argument.This is equivalent to the following:
new_func = a(b)
new_func(c)
An example:
In [1]: def multiply_by(x):
...: def multiply_by_x(y):
...: return x * y
...: return multiply_by_x # notice no parens
...:
In [2]: multiply_by(10)
Out[2]: <function __main__.multiply_by_x>
Notice when you call this you get a function object. (This is what I mean when I am saying a "reference to a function" or the like.)
In [3]: multiply_by(10)(5)
Out[3]: 50
You're calling the function returned by multiply_by()
with 5 as an argument, and it's exactly the same as doing:
In [4]: multiply_by_10 = multiply_by(10)
In [5]: multiply_by_10(4)
Out[5]: 40
In [6]: multiply_by_10(8)
Out[6]: 80
The cool thing about doing this, as you can see from this example, is that now your multiply_by
function is a factory for functions that multiply by something. Above, we created multiply_by_10
which, obviously, multiplies what you feed it by 10. We can just as easily do:
In [7]: multiply_by_5 = multiply_by(5)
and have a function that multiplies by 5. This is obviously extremely useful. Incidentally, it's also how Python's decorators work.
Thanks @MarkusMeskanen in the comments for pointing out a way to make my silly example into a cooler one!
See also:
The key is that wraps()
takes a function as its parameter and returns a function, probably with some extra goodness added to it, sort of like what a decorator function does.
If you were to print(wraps(func))
you should see output that identifies the object as a function.
So wraps(func)(self)
can be rewritten as
wrapped_func = wraps(func)
wrapped_func(self)
which looks more "normal" to some people.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With