How can a function takes another function WITH arguments, as a parameter?
Question:
def Wrapper(func):
def MyPrint(message):
print('Hello ' + message)
func(MyPrint)
Wrapper(lambda my_print: my_print('world'))
I’m confused of the above code. I get that a function can take another function as parameter and use func()
to invoke it, but how can Wrapper(lambda my_print: my_print('world'))
call the inner function MyPrint
? The func
is a parameter, and the lambda my_print: my_print('world')
is its argument, but somehow the argument seems to utilizes (penatrate through) an inner function inside Wrapper
.
This is a very common pattern in JavaScript but confuses me. I think an explaination of what happened in detail might help.
Answers:
Simplest answer:
You are renaming in the local scope of ‘Wrapper’ function.
Detailed answer:
When ‘Wrapper’ gets called, it takes the throw away function lambda my_print: my_print('World')
(now becomes ‘func’ in ‘Wrapper’ local scope). The throw away function needs the variable ‘my_print’ to be a function or it’ll throw an error. That function must also take a variable itself, a preset string (‘World’). ‘MyPrint’ predefined in the local scope of ‘Wrapper’ function, gets renamed as ‘my_print’, which takes the preset argument ‘World’ string. When ‘func’ is called (in local scope of ‘Wrapper’), it return ‘World’ string as the argument for ‘my_print’ (which is ‘MyPrint’ just renamed) function. This prints ‘Hello World’ to the screen before the ‘Wrapper’ function closes out. When it closes, you are back in the global scope.
(lambda my_print: my_print('world')
doesn’t call MyPrint
directly; MyPrint
is passed as its argument in func(MyPrint)
.
Try the substitution method:
Wrapper(lambda my_print: my_print('world'))
—>
func
is bound to lambda my_print: my_print('world')
in the body of Wrapper
:
def MyPrint(message):
print('Hello ' + message)
(lambda my_print: my_print('world'))(MyPrint)
—>
my_print
is bound to MyPrint
in the body of the lambda:
def MyPrint(message):
print('Hello ' + message)
MyPrint('world')
Addendum: the same, but with a non-local function and no lambda, in case that makes it clearer:
def GreetingPrinter(message):
print('Hello ' + message)
def Wrapper(func):
func(GreetingPrinter)
def PrintWithWorld(printer):
printer('World')
Wrapper(PrintWithWorld)
def Wrapper(func):
def MyPrint(message):
print('Hello ' + message)
func(MyPrint)
Wrapper(lambda my_print: my_print('world'))
I’m confused of the above code. I get that a function can take another function as parameter and use func()
to invoke it, but how can Wrapper(lambda my_print: my_print('world'))
call the inner function MyPrint
? The func
is a parameter, and the lambda my_print: my_print('world')
is its argument, but somehow the argument seems to utilizes (penatrate through) an inner function inside Wrapper
.
This is a very common pattern in JavaScript but confuses me. I think an explaination of what happened in detail might help.
Simplest answer:
You are renaming in the local scope of ‘Wrapper’ function.
Detailed answer:
When ‘Wrapper’ gets called, it takes the throw away function lambda my_print: my_print('World')
(now becomes ‘func’ in ‘Wrapper’ local scope). The throw away function needs the variable ‘my_print’ to be a function or it’ll throw an error. That function must also take a variable itself, a preset string (‘World’). ‘MyPrint’ predefined in the local scope of ‘Wrapper’ function, gets renamed as ‘my_print’, which takes the preset argument ‘World’ string. When ‘func’ is called (in local scope of ‘Wrapper’), it return ‘World’ string as the argument for ‘my_print’ (which is ‘MyPrint’ just renamed) function. This prints ‘Hello World’ to the screen before the ‘Wrapper’ function closes out. When it closes, you are back in the global scope.
(lambda my_print: my_print('world')
doesn’t call MyPrint
directly; MyPrint
is passed as its argument in func(MyPrint)
.
Try the substitution method:
Wrapper(lambda my_print: my_print('world'))
—>
func
is bound to lambda my_print: my_print('world')
in the body of Wrapper
:
def MyPrint(message):
print('Hello ' + message)
(lambda my_print: my_print('world'))(MyPrint)
—>
my_print
is bound to MyPrint
in the body of the lambda:
def MyPrint(message):
print('Hello ' + message)
MyPrint('world')
Addendum: the same, but with a non-local function and no lambda, in case that makes it clearer:
def GreetingPrinter(message):
print('Hello ' + message)
def Wrapper(func):
func(GreetingPrinter)
def PrintWithWorld(printer):
printer('World')
Wrapper(PrintWithWorld)