Local Function Call on itself - python

Learning python, searched for this problem, and having a hard time figuring out why I'm getting the behavior that I am. I'm getting the correct output, but I'm not sure why, I'd just like to know going forward just to better understand this concept. Let me explain:
if create a function such as
def function(list):
and I then call this function on a list x
print function(x)
if I were then to recall this function with the function itself like so:
def function(list):
function(list)
why does that recursive call still hold the values for x which was called globablly?

The "list" in the parameter list is then passed to the next call. Each one is a direct copy of x. It's not the global x; it's the local copy in the variable list that gets passed down.
Note that this is a direct example of infinite recursion: there's no way to stop the chain of the function calling itself. Instead, you might want something like
def function(list):
if len(list) == 0:
return "end"
else
return function(list[1:]) + list[0]
A recursive function needs a terminating condition and something to return.

Related

when do we initialise a function call within the function vs as an argument?

I have a question about arguments in functions, in particular initialising an array or other data structure within the function call, like the following:
def helper(root, result = []):
...
My question is, what is the difference between the above vs. doing:
def helper(root):
result = []
I can see why this would be necessary if we were to run recursions, i.e. we would need to use the first case in some instances.
But are there any other instances, and am I right in saying it is necessary in some cases for recursion, or can we always use the latter instead?
Thanks
Python uses pointers for lists, so initializing a list or any other mutable objects in function definition is a bad idea.
The best way of doing it is like this:
def helper(root, result=None):
if isinstance(result, type(None)):
result = []
Now if you only pass one argument to the function, the "result" will be an empty list.
If you initiate the list within the function definition, by calling the function multiple times, "result" won't reset and it will keep the values from previous calls.

Running function code only when NOT assigning output to variable?

I am looking for a way in python to stop certain parts of the code inside a function but only when the output of the function is assigned to a variable. If the the function is run without any assignment then it should run all the inside of it.
Something like this:
def function():
print('a')
return ('a')
function()
A=function()
The first time that I call function() it should display a on the screen, while the second time nothing should print and only store value returned into A.
I have not tried anything since I am kind of new to Python, but I was imagining it would be something like the if __name__=='__main__': way of checking if a script is being used as a module or run directly.
I don't think such a behavior could be achieved in python, because within the scope of the function call, there is no indication what your will do with the returned value.
You will have to give an argument to the function that tells it to skip/stop with a default value to ease the call.
def call_and_skip(skip_instructions=False):
if not skip_instructions:
call_stuff_or_not()
call_everytime()
call_and_skip()
# will not skip inside instruction
a_variable = call_and_skip(skip_instructions=True)
# will skip inside instructions
As already mentionned in comments, what you're asking for is not technically possible - a function has (and cannot have) any knowledge of what the calling code will do with the return value.
For a simple case like your example snippet, the obvious solution is to just remove the print call from within the function and leave it out to the caller, ie:
def fun():
return 'a'
print(fun())
Now I assume your real code is a bit more complex than this so such a simple solution would not work. If that's the case, the solution is to split the original function into many distinct one and let the caller choose which part it wants to call. If you have a complex state (local variables) that need to be shared between the different parts, you can wrap the whole thing into a class, turning the sub functions into methods and storing those variables as instance attributes.

returning values of function in python

Why do I have to return function in the else case? Can't I just apply the defined function because I have to only return the value of b and store it?
def gcd_a(a,b):
if a==0:
return b
else:
gcd_a(b%a,a)
I think the main concept you are missing is that in order to get the result of a recursive function (or any function for that matter), the function that you access the result of must return the value*
Right now, when you call gcd_a, a recursive call to gcd_a will eventually return a value, however it will be lost, since the function that you are accessing the result of does not return a value.
To show you this is true, let's add in a log statement that prints when the function is returning:
def gcd_a(a,b):
if a==0:
print('finally returning!', b)
return b
else:
gcd_a(b%a,a)
Now if we call:
print(gcd_a(10, 99))
We get the following output:
finally returning! 1
None
Somewhere, a recursive call to gcd_a found your condition to be True, and returned 1, however, this result is not printed, because it is not returned by your call to gcd_a
* Unless you do something strange like updating a global variable, etc...
If your function finishes without returning anything, it will implicitly return None.
def double(val):
val * 2
value = double(10)
print(value)
Which is fine, except it doesn't have a return statement, and so all you get is None
The same applies to recursive functions: you can do all the recursive function calls you want, but if you don't actually return the result of the function, then it'll return None.
IMHO, the problem is in the way you are thinking about function which has to be cleared. The fact that you are having this doubt in a recursive function call is incidental because you are calling the same function again and again with different arguments causing different branches to be executed.
How will a function that doesn't return anything in any of its branches be helpful to its caller? In your case, what would happen if your function's caller calls it with an argument that hits your else block? It will return nothing and this won't help the caller!
Now in your recursive case, if your caller calls the function with an argument that hits the if block, then it would work as expected. However, if it hits the else block, then it would become a caller and call the same function again. For simplicity, let us assume that this time it hits the if condition and returns something to its caller. However, will that reach the original caller that initiated everything? The answer is no because you are not returning it to him!
Most of the times you would need a return for every branch in a function
unless you are doing it on purpose for a side effect.
In the else block, if you don't return the function call, the outer function returns None because python interpreter just runs whatever is returned by the gcd function.
Let's assume the following code:
def func():
10
In that function, it just runs 10, but it doesn't mean that there is some return from the function.

Parentheses in Python's functions and decorators(wrappers)

Thanks for reading my question. As I'm still new to Python, I would like to ask about the () in Python.
def addOne(myFunc):
def addOneInside():
return myFunc() + 1
return addOneInside # <-----here is the question
#addOne
def oldFunc():
return 3
print oldFunc()
Please note that on line four, although the programme returns a function, it does not need parentheses(). Why does it NOT turn out with an error for syntax error? Thank you very much for your answers in advance!
The parentheses are used to run a function, but without them the name still refers to the function just like a variable.
return myFunc() + 1
This will evaluate the myFunc function, add 1 to its value and then return that value. The brackets are needed in order to get the function to run and return a numeric value.
return addOneInside
This is not actually running addOneInside, it is merely returning the function as a variable. You could assign this to another name and store it for later use. You could theoretically do this:
plusOne = addOneInside
plusOne()
And it will actually call the addOneInside function.
The particular instance in your initial question is known as a Decorator, and it's a way for you to perform code on the parameters being passed to your function. Your example is not very practical, but I can modify it to show a simple use case.
Let's say that you want to only have positive numbers passed to your function. If myFunc is passed a negative number, you want it to be changed to 0. You can manage this with a decorator like this.
def addOne(myFunc):
def addOneInside(num):
if num < 0:
num = 0
return myFunc(num)
return addOneInside # <-----here is the question
#addOne
def oldFunc(number):
return number
To explain, the #addOne is the decorator syntax, and it's attaching the addOneInside function to be called on the argument/s of oldFunc whenever you call it. So now here's some sample output:
oldFunc(-12)
>>> 0
oldFunc(12)
>>> 12
So now you could add logic to oldFunc that operates independently of the parameter parsing logic. You could also relatively easily change what parameters are permitted. Maybe there's also a maximum cap to hit, or you want it to log or note that the value shouldn't be negative. You can also apply this decorator to multiple functions and it will perform the same on all of them.
This blogpost explained a lot for me, so if this information is too brief to be clear, try reading the long detailed explanation there.
Your indentation in function addOne() was incorrect (I have fixed it), but I don't think that this was your problem.
If you are using Python3, then print is a function and must be called like this:
print(oldFunc())

What happened when I change the variable 'x' to 'fab'?Something about decorator and pass the function variable

I define a Factorial function named fab. I use generator to avoid stack overflow.But something I can't understand came up when I try to write a decorator version, which is more intuitive :
import types
def TCO(f):
def inner(*nkw,**kw):
gen=f(*nkw,**kw)
while isinstance(gen,types.GeneratorType):
gen=gen.next()
return gen
return inner
def fab(n,s=1):
if n<2:
yield s
else:
yield fab(n-1,s*n)
x=TCO(fab)
print x(2500) #this works fine, overcoming the limitation of tail-recursion.
fab=TCO(fab) #now just change the variable name.
print fab(5) #this woks fine.
print fab(2500) #this will raise an error :maximum recursion limit exceeded
Why? I know it has something to do with the same name fab, but why fab(5) works fine? I think when I define fab=TCO(fab), I actually change the object refered by f in inner to object TCO(fab). So when fab(5) runs, the gen will never be a generator! Because the inner never returns generator!
I am mad...Why ?
fab=TCO(fab)
statment now makes the variable fab points to the function inner. After that, when
yield fab(n-1,s*n)
is encountered, it is not actually calling the original fab function but the inner function which in turn calls the original fab function. Basically, you are coming out of the generator and entering another function every time. Thats why you are getting maximum recursion limit exceeded error.
I think this would be a good example to explain what happens:
def f(x):
print 'original'
if x > 0:
return f(x-1)
return 0
g = f
def f(x):
print 'new'
return x
print g(5)
result:
original
new
4
this proves:
1.when g(5) runs, origninal `f` is called, not new `f`.
2.as 5>0, 'return f(x-1)' is executed
3.new `f` is called when `f(x-1)` runs. so the result is 4.
Your original version yields a generator which yields a generator which yields a generator, etc. To evaluate that linked list you then use the while loop in you TCO decorator. It all is based on the fact that you are linking generators to avoid a large stack.
This concept is broken when you assign something new to the variable fab. Then yielding fab(n-1, s*n) in fab is accessing the new fab variable and thus not returning a generator anymore but a value. To compute that value, the stack is used, hence you can get the stack overflow problem.

Categories