I'm a python beginner and I struggle with a somewhat easy concept of functional programming. I simply can not see why the nested function (see example below) would even be called. This is quite hard to explain.
func3 = func1(func2)
Here I call func1 with the positional argument func2. All fair and well. func1 returns a nested function. But when I run the code the function nest1has been executed even though I've only called func1 (I dont see why this should execute the nested function). func1 should not do more than returning a function without printing anything. Can someone explain this to me?
def func2():
def nest2():
print('Nest2')
nest2()
return nest2
def func1(func):
def nest1():
print('Nest1')
func()
return nest1
func3 = func1(func2)
func3()
If I call a simple function with a nested function the inner function is not executed. See below:
def new_func():
def inner():
print(1)
return inner
new_func()
func1() returns the method nest1 (without executing it), so your call func3 = func1(func2) returns nest1 and assigns it to func3.
The next line you are executing whatever is assigned to func3 - which is the method nest1. In other words, the line func3() is executing the function nest1, and causing the text to print.
But when I run the code the function nest1 has been executed even though I've only called func1 (I dont see why this should execute the nested function). Func 1 should not do more than returning a function without printing anything. Can someone explain this to me?
When you do this:
func3 = func1(func2)
You pass the function func2 into the function func1. Inside of func1, you define a function nest1 that calls the function passed in. This function is then returned and becomes the value of func3. The only thing func1 does is create the nest1 function, and return it. When func3 is called, you actually called the function defined inside of func1, nest1.
If I call a simple function with a nested function the inner function is not executed.
The reason your second example did not work as expected, is because calling new_func does not call inner, it only creates inner and returns it. This is the same case as above. Calling func1 did not call nest1, it simply created nest1 and returned it. You had to explitly call nest1 (func3()). Likewise, you need to call the function returned from new_func explicitly:
new_func()()
In the final example, you need to call the function that is being returned with an extra ():
def new_func():
def inner():
print(1)
return inner
new_func()()
Output:
1
Body of func2 is:
def nest2():
print('Nest2')
nest2()
return nest2
And so body of func1(func2) is:
print('Nest1')
def nest2():
print('Nest2')
nest2()
return nest2
The last piece we get by replacing func with body of func2 in body of nest1.
Related
def outer_fun(func):
print('outer function ran')
def inner_function():
print('inner function ran')
return func()
return inner_function()
def fun():
print("Hi")
fun = outer_fun(fun)
print(fun)
the output is:
outer function ran
inner function ran
Hi
None
why the none here?
when I do
fun = outer_fun(fun)
and calls it immediately inside the inner_function it runs fun() and makes the fun a none object? why?
Also if I try to run fun = outer_fun(fun) again it says object is not callable
In a simple word your None is occur for this code
def fun():
print("Hi")
because its return Nothing, if you return something then it can show this instead of None. If you don't want to see None then use fun instead of print(fun).
fun() implicitly returns None. So when you set
fun = outer_fun(fun)
you have set fun to None. Before that assignment, fun is a function.
When you repeat that call, fun is already None, so you are doing this:
fun = outer_fun(None)
which as you note fails because None is not callable.
From the subject of your question, it seems you are trying to write a decorator. Your decorator has to return a function (typically an inner function or closure). If your decorator doesn't return anything, then you'll probably see the behavior you are trying to understand.
Your outer function ends with:
return inner_function()
which should be:
return inner_function
ie: return the function, not call the function and return whatever it returns.
I'm learning the lambda options to return in python and i have a question:
I need to fill the returns in this function:
def func(n):
if n==0:
print("finished")
else:
return ___
func(5)()()()()()
func(3)()()()
func(8)()()()()()()()()
The output:
finished
finished
finished
I thought this one is a recursive call like return func(n-1) but it doesn't work, and throws an error.
Is there an option to overcome the extra empty brackets? count them? do something, because it should be runnable.
Thanks
You're right about needing to use lambdas and func n-1, specifically
return lambda: func(n-1)
This returns a lambda that doesn't need any parameters passed in, to handle the brackets, and the return of the is the function being called with n-1, which in most calls you're making, is returning the next lambda function call
The operator () is the function call.
So for example:
def foo():
print('Foo executed')
def bar():
# We return the foo FUNCTION itself, without calling it.
return foo
In the above code, if you execute foo(), it'll print "Foo executed". But if you execute bar(), it will return foo, which is the function. So you can execute bar()(), where the first () is executing the function bar, returning foo, and then with the second (), you call the returned foo function.
Edit: When I typed it, you removed the what are those bunch of () because they are new to you... But I just leave it there maybe it'll help.
I'm trying to understand the behavior of decorator.
I understand that a decorator has to return an object so I can understand the syntax below:
def my_deco(fonction):
print("Deco is called with parameter the function {0}".format(fonction))
return fonction
#my_deco
def hello():
print("hello !")
Deco is called with parameter the function <function salut at 0x00BA5198>
Here the decorator does not do much, but in the case I need to modify the function, I'd define a decorator like this
def my_deco(fonction):
def modified_func():
print("Warning ! calling {0}".format(fonction))
return fonction()
return modified_func
#my_deco
def hello():
print("Salut !")
The initial function behavior is modified through modified_func.This is fine
It includes the call to the initial function. This is fine
Now what I don't understand is: why do we return the result of the function? in my case the function is a simple 'print' so I don't get why I should return something
Thanks for your explanation
As it is in the comments: usually when you write a decorator, you make it so that it can be used with any possible function. And the way to do that is to return either whatever the original function returned, or transform that return value (which can also be done in the wrapper function).
In Python, all functions actually do return something. Functions without an explicit return statement return the value None. So, if your wrpper function, inside the decorator, always returns whatever the decorated function returned, it will be on the safe side: even if the decorated function had no explicit return, it will return a None that is just forwarded by your wrapper.
Now, that is not "mandatory". If you know beforehand that your decorator will only be applied to functions with no return value, you are free not to put a return statement in the wrapper function as well - it is not an incorrect syntax (but it is likely a trap for your future self).
def func():
def nested():
global x
x = 1
x = 2
func()
print(x)
The correct answer would be '2' and the reason why is because func() is not defined. But when I read this it seems that func() is defined as nested(). I would think that when you call func() that would then automatically call nested(). I'm struggling to grasp this and understand why I shouldn't read it that way.
You're defining nested inside func, but you're not calling nested() anywhere in func, so when you call func() it's effectively doing nothing.
To do what you want try defining func as:
def func():
def nested():
global x
x = 1
nested()
UPDATE: After StevenRumbalski's comment, I think a small addition about what exactly is going on in that function can help clarify things around.
Python's functions are themselves objects which can respond to the operator ().
When you define a new function, what you're actually doing is instantiating a function object and giving it a name. In the example above, def func() creates a function instance and gives it name func, so that when you apply operator () to func (i.e. when you call the function with func()) the code of the function associated to that name is executed.
Let's now take one step further and look at what happens with nested.
Nested is defined inside func's scope, so when you exit func's scope the name nested is not defined anymore.
If, however, you return the function object to the caller of func, you can use that object to run nested's code.
A small example:
def returning_func():
def nested():
print("I am nested!")
return nested # note the lack of the () operator!
In this case, if we do
my_reference_to_nested = func()
nothing gets printed, because nested is defined but not executed.
If we call it, however:
my_reference_to_nested()
we execute nested's code and print to the output I am nested!
I am trying write a decorator in python 3 which basically keeps a count on the number of times a function gets called.
Here is my code:
def call_counter(func):
def helper(x):
helper.calls += 1
return func(x)
helper.calls = 0
return helper
#call_counter
def succ(x):
return x + 1
for i in range(10):
print(succ(i)) # <--- ??
I understand how decorator works but only confusion I have here is that the first ever call to succ(x) gets a function in return #call_counter decorator.
However the main confusion here is I dont quite understand how sequential calls inside the for loop happens here?
So how does the flow go after we have a returned function (helper in this case) from first call.
Now inside the for loop, succ(0), succ(1) and so on gets called, how does that work? Do we reuse the same returned function that we got from the first call or does decorator gets called everytime the for loop gets added by 1?
The decorator is applied only once when it is met and after that all invocations of succ use the same function you've returned helper.
This can be seen if you just printed the function object inside the for loop instead of calling it:
for i in range(10):
print(succ)
<function call_counter.<locals>.helper at 0x7fe4d05139d8>
<function call_counter.<locals>.helper at 0x7fe4d05139d8>
# ... so on, ten times.
The flow is straight-forward, helper is called each and every time with the argument x which is passed to func.