Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

what is function(var1)(var2) in python

Tags:

python

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

like image 705
codyc4321 Avatar asked Nov 30 '22 10:11

codyc4321


2 Answers

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:

  • The function 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:

  • What is a closure?
  • Python Decorators Demystified
  • functools
like image 67
Two-Bit Alchemist Avatar answered Dec 04 '22 06:12

Two-Bit Alchemist


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.

like image 45
Peter Rowell Avatar answered Dec 04 '22 06:12

Peter Rowell