0

I'm trying to understand how Python processes the code in the examples below:

When cake()() is executed, Python first prints 'beets' then prints 'sweets'

However, when chocolate() is executed, Python only prints 'sweets'

Could someone explain the difference for the 2 scenarios?

Also when more_chocolate is executed, Python does not print any values, it simply returns 'cake'.

I'm sure there's a tidy explanation for these cases. Hope someone can explain!

def cake():
    print('beets')
    def pie():
        print('sweets')
        return 'cake'
    return pie

chocolate = cake()

cake()()

chocolate()

more_chocolate, more_cake = chocolate(), cake

more_chocolate
martineau
  • 119,623
  • 25
  • 170
  • 301
  • after `chocolate = cake()` (which also prints `beets`) you have `chocolate = pie` so when you use `chocolate()` then you runs `pie()` which can print only `sweets` – furas Jul 14 '19 at 10:51
  • 1
    what is the meaning of extra indentation between `print('beets')` and `def pie()`? it would produce a syntax error as it's written currently – Aprillion Jul 14 '19 at 10:52
  • 1
    `cake()()` works like two other lines `chocolate = cake()` and `chocolate()` – furas Jul 14 '19 at 10:54
  • I get it now. Thank you! – Benjamin Lu Jul 14 '19 at 10:55

3 Answers3

1
chocolate = cake()

This binds the identifier chocolate to the object returned by invoking cake - it returns a function object - therefore, chocolate is bound to that function object (chocolate is bound to the function object pie). A side effect of invoking cake is is that "beets" is printed.

cake()()

This invokes cake, which returns a function object. This time the function object is not bound to a name. Upon returning we invoke the anonymous function object. The result is "beets" is printed from the call to cake, and "sweets" is printed from the call to pie. pie also returns the string "cake", but that string is not bound or captured.

chocolate()

chocolate is still bound to the function object returned by cake when we did chocolate = cake(). Now we are simply invoking the function object we captured earlier. Since we are not actually calling cake now (we're only calling pie), "beets" is not printed, but "sweets" is. Again, this returns the string "cake", but again, it is not bound or captured.

more_chocolate, more_cake = chocolate(), cake

this binds more_chocolate to the object returned by calling chocolate (which is the string "cake"). It also binds more_cake to cake. Not sure if you actually meant to do this - all this does is it binds more_cake to the same function object that cake is bound to, but you're not actually invoking any function here.

Paul M.
  • 10,481
  • 2
  • 9
  • 15
0

When you execute cake(), the following chunk is run:

print('beets')
def pie():
    print('sweets')
    return 'cake'
return pie

So it:

  • prints beets
  • executes the pie function definition, the function body is not run yet hence no printing of sweets
  • returns the pie function object

You're saving the returned function object as name chocolate, so it now refers to the pie function object.

So when you execute chocolate(), it actually runs pie() now and does the following:

  • prints sweets
  • returns string cake

When you do cake()() it also does the same thing without using the intermediate variable chocolate. So cake()() runs the returned function object from cake() i.e. pie with the prints.

heemayl
  • 39,294
  • 7
  • 70
  • 76
0

The concept is called Currying Function. In functional programming, currying is the way to simplify multiple arguments function into a simpler function with a single argument.

To understand the behavior of your example lets break it down:

def cake():
    print('beets')
    def pie():
        print('sweets')
        return 'cake'
    return pie

Here we have a function cake which is going to print beets and return a function pie.

Now if we invoke it using:

cake()()

Here we invoked it twice, first when cake() will be executed it will print beets and return pie function which immediately going to get invoked due to the second set of () results printing sweets

While if we execute it:

chocolate = cake()

We executed only one time so it will print beets and returning pie function will be set into the variable chocolate.

and later when we invoke chocolate it will print sweets also it returns a string cake. Which you in later case save in more_chocolate variable. Since it is just a string literal and not printing anything that's the reason nothing get printed on the output.

Zaheer Ahmed
  • 28,160
  • 11
  • 74
  • 110