Don't understand how this nested function works [duplicate] - python

This question already has answers here:
Why aren't python nested functions called closures?
(10 answers)
Closed 2 years ago.
def raise_val(n):
def inner(x):
raised = x**n
return raised
return inner
square = raise_val(2)
print(square(2))# gives 4 as output
I don't understand how this nested function works...also why does square(2) output 4?
Isn't square just a variable?

This is called higher-order functions in functional programming languages. Python also uses this paradigm.
A higher-order function is a function that either/both accepts a function as an argument and/or returns a function as a result. Your function raise_val is a higher order function in the sense that it is returning back a function. Your variable square has a function (the inner).
When you call raise_val(2) what you do is that you return a partial function that needs to be evaluated. Then with square(2) you are passing 2 to the inner partial function that uses the 2 for n when you initially called raise_val(2).

In python, functions are values, too.
So, every time that you call raise_val, you are generating a new "inner" function which has a different constant for the n variable.
You are assigning this new function to the variable square, and then calling this new function.

When you type square = raise_val(2), you provide the n=2 parameter to inner and raise_val returns you the inner function and stores it in thesquare variable.
def raise_val(n):
def inner(x):
raised = x**n
return raised
return inner # This returns a function, not a number!
This is why you can call square later by writing square(2). Here you provided the x=2 argument.
print(square(2))# gives 4 as output
What you did is equivalent to printing raise_val(n=2)(x=2).

Line by line explanation:
def raise_val(n): begin defenition of a function, raise_val, which accepts n as a parameter.
def inner(x): begin defenition of a function within raise_val, called inner, which accepts x as a parameter
raised = x**n set variable raised as x(the argument given to inner) to the power of n(the argument given to raise_val)
return raised return raised as the return value of inner
return inner return the function inner as the return value of raise_val
square = raise_val(2) set a new variable square as the output of the function raise_val when called with an argument 2, which will be a function that takes a number x and return it squared
print(square(2)) call the variable square with paramter 2, thus returning 2 to the power 2, or 4, which it then prints

Related

Understanding Python nested function sample

This link talks about Python nested functions.
They have this example:
def num1(x):
def num2(y):
return x * y
return num2
res = num1(10)
print(res(5))
When I run it, it multiplies 10 by 5 and prints out 50. How does it "run"
res = num1(10)
... if the num1() function is only given a single argument of 10? y is not defined when num1(10) is run. The print function only executes when it runs res(5), but how are you "stuffing" two values into x in the parent function?
I'm thinking there's a bigger picture thing I'm not understanding in relation to how the function and order is running.
Thanks for looking at this beginner question. I'm just trying to understand... baby steps.
When you run res = num1(10) it assigns a function to res, but doesn't run it.
You can kind of think of it like this (not valid syntax, only for illustration):
res = def num2(y):
return 10 * y
Then when you call res, it actually runs the function and does the multiplication.
You supply y when you do res(5); y isn't given a value when num1 is run.
num1 returns a function that will require y. y is supplied when that returned function is called.
This is a common technique to delay the need for supplying information to a function. If a function accepts two parameters but you only have one of the arguments handy, you can return a function that wraps a call to the function where the known parameter already passed. You're left with a function that accepts the remaining data when it becomes available.

Why does this function need to be stored in a variable?

I originally had a problem with this code as I was missing the 'n =' in the last line of code and, as a result, was stuck in an infinite loop.
At this point, while I understand what needed to be corrected I don't understand why. Why can't 'collatz(n)' be enough to call the function and use n as its variable? If anyone could explain this in simple terms (beginner here), I'd really appreciate it.
def collatz(number):
if number % 2 == 0:
print (number // 2)
return number // 2
elif number % 2 == 1:
print (3 * number + 1)
return 3 * number + 1
print ('Please enter a number.')
n = int(input())
while n != 1:
n = collatz(n)
In Python, functions accept one or more arguments and return a single value or object. Most of the time they don't modify their arguments (and indeed your collatz function doesn't attempt to modify its argument).
As an example, this function accepts a variable x, and returns x**2.
def f(x):
return x**2
This function doesn't modify x in place, and the return value won't automatically get assigned to x. Automatic assignment to x would often be unhelpful, and it would be unclear what to do if your function accepted multiple arguments -- which one should get the return result?
You can call this function in various ways, but if you want to do something with the result, you have to store it to a variable or use it immediately:
y = 2
z = f(y)
z = f(2)
y = 2
print(f(y))
Note that all of these make sense if you think of the function f as an object that converts its argument to something else and returns that, but none of them make sense if you expect f to modify its argument in place (then f(2) would somehow have to convert the number 2 to mean 4 during later references).
For what it's worth, even if you did replace one of the arguments with a new value inside the function, that would not change the value of the corresponding variable outside the function. This is because the variables within the function only point to the corresponding value or object. If you assign a new value to the variable, the local variable within the function will now point to the new value, but the original variable outside the function still points to the old value. On the other hand, you can sometimes modify the underlying value or object rather than creating a new object and pointing the local variable to it. For example, adding an item to a list or dictionary will modify the underlying object, and that change will be visible outside your function.
But your collatz function does neither of these - it just calculates a new value and returns it. If you want to do anything with that value, you have to store the result of the function call explicitly. It won't automatically be stored in the argument variable.
When you pass a variable as an argument to a function, a copy of the variable is sent to the function and not the variable itself.
So in your case n_copy (for example) is sent to your function and not n.
Now when you modify it within the function it remains in the scope of the function (accessible only by the function) and not the main program.
So when the function ends, nothing happens to n because a copy of n was modified.
Now we come to the return function. Because of the above problem, there is a return function. This will return a value from the function to the main program.
As you modified n within your function, you need to return the modified value to the main program.
Once you return it to the main program, it has to be stored in a variable, in your case it is n.
As you have started learning Python, you should read about namespace, scopes also.
Here is the first link from google search
https://matthew-brett.github.io/teaching/global_scope.html

Differences between return function in python and Matlab

Comparing MATLAB and Python, it appears that there are some differences between return command in Python vs MATLAB. Is there an exact equivalent for MATLAB return function in python?
The use of the return keyword is different in a Python function vs. a MATLAB function.
In a MATLAB function, the Left Hand Side (LHS) arguments define what needs to be defined within the function body prior to returning.
function y = foo(x)
y = 1;
end
If you use a return statement to end execution of the function early, you still are responsible for correctly populating the LHS argument list of the function
function y = foo(x)
y = 1;
return;
y = 2;
end
In this example, foo returns 1 as y because the function body defines y to be 1, before execution returns to the caller after the return statement.
In python, the return statement ends execution AND also defines what (if any) values are returned by a function, there is no output argument list in a python function definition.
def foo(x):
return 1;
Because you need to use the return keyword in python to return values from a function, return tends to be a more heavily used construct than return in MATLAB function definitions.

Please help me translate the following lambda to human language

What do the following expression actually does?
list = [lambda n=n: lambda x: x+n for n in range(10)]
More specifically:
What does n=n mean?
What will be the content of 'list'?
What will be the output of
print(list[0](14)) and print(list[0]()(14))
and why?
What does n=n mean?
lambda lets you define functions that take parameters, just like def. And those parameters can have default argument values. So, lambda n=n: is the same as def foo(n=n):.
In fact, when faced with an expression that's too complicated for you to read, it's often worth unpacking into simple statements:
list = []
for n in range(10):
def spam(n=n):
def eggs(x):
return x+n
return eggs
list.append(spam)
Now, why would you want to create a parameter named n with default value n? Why not just lambda:? The official FAQ explains this, but let's try to summarize.
If you just write this:
funcs = [lambda: n for n in range(10)]
… what you get is 10 functions of no parameters, that are all closures over the same variable, n. Because n has the value 9 at the end of the loop, when called, they're all going to return 9.
But if you do this:
funcs = [lambda n=n: n for n in range(10)]
… what you get is 10 functions of one optional parameter n (which hides the closure n from view), whose default value is the value of n at the time each function was defined. So, when called with no arguments, the first one will return 0, the second 1, and so on.
In your case, of course, the functions aren't just returning n, they're returning a function that takes a parameter, adds n to it, and returns the result. But the idea is the same; you want them to return different functions, which add 0, 1, … 9 to their arguments, not all return equal functions that all add 9.
What will be the content of list?
list will be 10 functions of one optional parameter whose default values range from 0 to 9, each of which returns a function of one parameter. That returned function is a closure over the value of n from the outer function. So, when it's called, it returns its argument, x, plus the n variable that ranges from 0 through 9.
What will be the output of
print(list[0](14))
Here, you're calling the first outer function, list[0], with the argument 14. So, instead of its default value 0 for n, it's going to have 14. So, what you'll get is a function that takes one argument and adds 14 to it. But it will print out as something like:
<function <listcomp>.<lambda>.<locals>.<lambda> at 0x105f21f28>
That long mess is Python 3.4+ trying to be helpful by telling you where to find the function definition. Usually, when a function is nested this deeply, most of the steps along the way have names. In this case, you've got three layers of anonymous functions, so none of the names are very useful…
In order to see it do anything useful, you'll have to call it:
print(list[0](14)(20))
And this will give you 34.
You could also use the inspect module, or just dir, to poke around inside the function. For example, print(list[0](14).__code__.co_freevars[0], list[0](14).__closure__[0].cell_contents) will tell you that it's stashed the number 14 under the name n for use by its internal function.
…
print(list[0]()(14))
Here, you're again calling list[0], but this time with no argument, so its n gets the default value of 0. So, it returns a function that adds 0 to its argument. You then call that function with 14, so you get 14.
To answer the last part first:
In [1]: list = [lambda n=n: lambda x: x+n for n in range(10)]
In [2]: print(list[0](14))
<function <lambda> at 0x7f47b5ca7cf8>
In [3]: print(list[0]()(14))
14
Obtained by running the code. list bad name by the way as list is a python builtin gives you 10 lambda functions that don't do much - the first will return the original argument x, the second the argument + 1, ect. as n is stored as the index of the lambda by n=n local to that lambda.

Python lambda closure scoping [duplicate]

This question already has answers here:
Creating functions (or lambdas) in a loop (or comprehension)
(6 answers)
Closed 6 months ago.
I am trying to use closures to eliminate a variable from a function signature (the application is to make writing all the functions needed for connecting Qt signals for an interface to control a largish number of parameters to the dictionary that stores the values ).
I do not understand why the case of using the lambda not wrapped in another function returns the last name for all cases.
names = ['a', 'b', 'c']
def test_fun(name, x):
print(name, x)
def gen_clousure(name):
return lambda x: test_fun(name, x)
funcs1 = [gen_clousure(n) for n in names]
funcs2 = [lambda x: test_fun(n, x) for n in names]
# this is what I want
In [88]: for f in funcs1:
....: f(1)
a 1
b 1
c 1
# I do not understand why I get this
In [89]: for f in funcs2:
....: f(1)
c 1
c 1
c 1
The reason is that closures (lambdas or otherwise) close over names, not values. When you define lambda x: test_fun(n, x), the n is not evaluated, because it is inside the function. It is evaluated when the function is called, at which time the value that is there is the last value from the loop.
You say at the beginning that you want to "use closures to eliminate a variable from a function signature", but it doesn't really work that way. (See below, though, for a way that may satisfy you, depending on what you mean by "eliminate".) Variables inside the function body will not be evaluated when the function is defined. In order to get the function to take a "snapshot" of the variable as it exists at function-definition time, you must pass the variable as an argument. The usual way to do this is to give the function an argument whose default value is the variable from the outer scope. Look at the difference between these two examples:
>>> stuff = [lambda x: n+x for n in [1, 2, 3]]
>>> for f in stuff:
... print f(1)
4
4
4
>>> stuff = [lambda x, n=n: n+x for n in [1, 2, 3]]
>>> for f in stuff:
... print f(1)
2
3
4
In the second example, passing n as an argument to the function "locks in" the current value of n to that function. You have to do something like this if you want to lock in the value in this way. (If it didn't work this way, things like global variables wouldn't work at all; it's essential that free variables be looked up at the time of use.)
Note that nothing about this behavior is specific to lambdas. The same scoping rules are in effect if you use def to define a function that references variables from the enclosing scope.
If you really want to, you can avoid adding the extra argument to your returned function, but to do so you must wrap that function in yet another function, like so:
>>> def makeFunc(n):
... return lambda x: x+n
>>> stuff = [makeFunc(n) for n in [1, 2, 3]]
>>> for f in stuff:
... print f(1)
2
3
4
Here, the inner lambda still looks up the value of n when it is called. But the n it refers to is no longer a global variable but a local variable inside the enclosing function makeFunc. A new value of this local variable is created every time makeFunc is called, and the returned lambda creates a closure that "saves" the local variable value that was in effect for that invocation of makeFunc. Thus each function created in the loop has its own "private" variable called x. (For this simple case, this can also be done using a lambda for the outer function --- stuff = [(lambda n: lambda x: x+n)(n) for n in [1, 2, 3]] --- but this is less readable.)
Notice that you still have to pass your n as an argument, it's just that, by doing it this way, you don't pass it as an argument to the same function that winds up going into the stuff list; instead you pass it as an argument to a helper function that creates the function you want to put into stuff. The advantage of using this two-function approach is that the returned function is "clean" and doesn't have the extra argument; this could be useful if you were wrapping functions that accepted a lot of arguments, in which case it could become confusing to remember where the n argument was in the list. The disadvantage is that, doing it this way, the process of making the functions is more complicated, since you need another enclosing function.
The upshot is that there is a tradeoff: you can make the function-creation process simpler (i.e., no need for two nested functions), but then you must make the resulting function a bit more complicated (i.e., it has this extra n=n argument). Or you can make the function simpler (i.e., it has no n=n argument), but then you must make the function-creation process more complicated (i.e., you need two nested functions to implement the mechanism).

Categories