Python infinite loop and if statement - python

The question requires me to determine the output of the following code.
def new_if(pred, then_clause, else_clause):
if pred:
then_clause
else:
else_clause
def p(x):
new_if(x>5, print(x), p(2*x))
p(1)
I dont understand why it will be an infinite loop.
of output 1,2,4,8,16....and so on.
From what i understand, passing print(x) as a parameter will
straightaway print x, that is why the output has 1,2,4 even though the predicate is not True.
What i dont understand is after x>5, when pred is True,
Why the function does not end at the if pred:
Is it because there is no return value? Even after i put return then_clause or else_clause it is still an infinite loop.
I am unable to test this on pythontutor as it is infinite recursion.
Thank you for your time.

Python doesn't let you pass expressions like x > 5 as code to other functions (at least, not directly as the code is trying to do). If you call a function like foo(x > 5), the x > 5 expression is evaluated immediately in the caller's scope and only the result of the evaluation is passed to the function being called. The same happens for function calls within other function calls. When Python sees foo(bar()), it calls bar first, then calls foo with bar's return value.
In the p(x) function, the code is trying to pass p(2*x) to the new_if function, but the interpreter never gets to new_if since the p calls keep recursing forever (or rather until an exception is raised for exceeding the maximum recursion depth).
One way to make the code work would be to put the expressions into lambda functions, and changing new_if to call them. Bundling the code up into a function lets you delay the evaluation of the expression until the function is called, and there's no infinite recursion since pred_func is generally going to return True at some point (though it will still recurse forever if you call something like p(0) or p(-1)):
def new_if(pred_func, then_func, else_func):
if pred_func():
then_func()
else:
else_func()
def p(x):
new_if(lambda: x>5, lambda: print(x), lambda: p(2*x))
Note that lambdas feel a little bit odd to me for then_func or else_func, since we don't care about or use the return values from them at all. A lambda function always returns the result of its expression. That's actually pretty harmless in this case, since both print and p return None anyway, which is the same as what Python would return for us if we didn't explicitly return from a regular (non-lambda) function. But for me at least, it seems more natural to use a lambda when the return value means something. (Perhaps new_if should return the value returned from whichever function it calls?)
If you don't like writing closures (i.e. functions that have to look up x in the enclosing scope), you could instead use functools.partial to bind pre-calculated arguments to functions like print and p without calling those functions immediately. For instance:
from functools import partial
def p(x):
return new_if(partial((5).__lt__, x), partial(print, x), partial(p, 2*x))
This only works if each of the expressions can be turned into a single call to an existing function. It can be done in this case (with a little creativity and careful syntax for pred_func), but probably won't be possible in more complicated cases.
Its also worth noting that the evaluation of 2*x happens immediately in the p function's scope, before new_if is called. If that multiplication was the expensive part of the else_func logic, that could be problematic (you'd want to defer the work to when else_func was actually called).

you are calling function from itself, that causes infinite loop and you have nothing to stop the function.
def new_if(pred, then_clause, else_clause):
if pred:
then_clause
else:
else_clause
def p(x):
if x<5:
new_if(x>5, print(x),p(2*x))
p(1)
this will solve it

Related

Inlining Python Function

In a C program, inlining a function is a fairly intuitive optimization. If the inlined function's body is sufficiently small, you end up saving the jump to the function and creation of the stack frame, and you store the return value wherever the function's result would have been stored, jumping to the end of the inlined function's "body" rather than long-jumping to the return pointer.
I'm interested in doing the same thing in Python, converting two python functions into another valid python function where the first got "inlined" into the second. An ideal solution to this might look something like the following:
def g(x):
return x ** 2
def f(y):
return g(y + 3)
# ... Becomes ...
def inlined_f(y):
return (y + 3) ** 2
Clearly, in a language as dynamic as Python, this isn't trivial to do automatically. The best generic solution I have come up with is to use dict to capture the arguments passed to the function, wrap the function body in a one-iteration for loop, use break to jump to the end of the function, and replace uses of arguments with indexes into the argument dictionary. The result looks something like the following:
def inlined_f(y):
_g = dict(x=y + 3)
for ____ in [None]:
_g['return'] = _g['x'] ** 2
break
_g_return = _g.get('return', None)
del _g
return _g_return
I don't care that it's ugly, but I do care that it doesn't support returns from within loops. E.g.:
def g(x):
for i in range(x + 1):
if i == x:
return i ** 2
print("Woops, you shouldn't get here")
def inlined_f(y):
_g = dict(x=y + 3)
for ____ in [None]:
for _g['i'] in range(_g['x'] + 1):
if _g['i'] == _g['x']:
_g['return'] _g['i'] ** 2
break # <-- Doesn't exit function, just innermost loop
print("Woops, you shouldn't get here")
_g_return = _g.get('return', None)
del _g
return _g_return
What approach could I take to this problem that avoids needing to use break to "jump" out of the inlined function's body? I'd also be open to an overall better, generic approach could I take to inline one Python function into another.
For reference, I'm working at the AST (abstract syntax tree) level, so using parsed Python code; clearly, outside of literal values, I don't know what value or type anything will have while performing this transformation. The resulting inlined function must behave identically to the original functions, and must support all features typically available when calling a function. Is this even possible in Python?
EDIT: I should clarify since I used the tag "optimization", that I'm not actually interested in a performance boost. The resulting code does not need to be faster, it just must not call the inlined function while still behaving identically. You can assume that both functions' source code is available as valid Python.
The only reasonable way on source level I see, simplified:
Parse the source into some AST (or just use the built-in AST).
Copy a subtree representing the function's body.
Rename the variables in the subtree, e.g. by adding an unique prefix.
At the call site, replace all passed arguments with assignments using the function's new variable names.
Remove the call and replace it with the function body you've prepared.
Serialize the AST back to source.
What poses real problems:
Generator functions; just don't inline them.
Returns from under try/finally that need to run the finally part. Might be pretty hard to rewrite correctly; imho, best left in-unlined.
Returns from under context managers that need to run the __exit__ parts. While not impossible, it's also tricky to rewrite preserving the semantics; likely also best left un-inlined.
Mid-function returns, especially from within multiple loop constructs. You might need to replace them with an extra variable and thread it into every condition of every while statement, and likely to add a conditional break to for statements. Again, not impossible but likely best left un-inlined.
Probably the closest analog to a return would be raising an Exception, which would work to pop out of nested loops to the top of the "inlined function".
class ReturnException(Exception):
pass
g = dict(x=y + 3)
try:
for j in some_loop:
for _g['i'] in range(_g['x'] + 1):
if _g['i'] == _g['x']:
raise ReturnException(_g['i'] ** 2)
except ReturnException as e:
_g['return'] = e.message
else:
_g['return'] = None
I don't know how much overhead is associated with exceptions though or if that would be faster than simply calling the function.

Python, why does this function go into an infinite loop

def new_if (pred,then_clause,else_clause):
if pred:
then_clause
else:
else_clause
def p(x):
new_if(x>5,print(x),p(2*x))
p(1)
I think the function should stop once x reaches 8 and 8 is printed out.
Thanks a lot for helping
Your code doesn't do what you think it does.
Every time you call p it executes the code inside that method, which in your case calls new_if with some arguments. However you are evaluating those arguments immediately, which means before entering new_if your code is executing print(x) and p(2*x). This causes p to get called again, repeating the process.
There seems to be some general confusion in how you think your code is evaluated: in particular, what you think as predicates and clauses really are not. The arguments are evaluated before the call to new_if is made. Hence, you get a infinite recursive call to p, by evaluating p(2*x) almost as soon as you call p.
You could achieve what you want by passing functions, which you then evaluate within your new_if function. This can be done with lambda functions, like so:
def new_if (pred,then_clause,else_clause):
if pred():
then_clause()
else:
else_clause()
def p(x):
new_if(lambda: x>5, lambda: print(x), lambda: p(2*x))
p(1)
In this case, pred, then_clause, else_clause are callables which you need to call (()) for them to be executed.

difference between printing and returning recursive function in python

When writing a recursive function in Python, what is the difference between using "print" and "return"? I understand the difference between the two when using them for iterative functions, but don't see any rhyme or reason to why it may be more important to use one over the other in a recursive function.
What a strange question.
The two are completely different, and their correct use in a recursive function is just as important as in an iterative one. You might even say more important: after all, in an iterative function, you return the result once only; but in a recursive function, you must return something at every step, otherwise the calling step has nothing to work on.
To illustrate: if you are doing mergesort, for example, the recursive function at each stage must return the sorted sublist. If it simply prints it, without returning it, then the caller will not get the sublist to sort, so cannot then merge the two sorted sublists into a single sorted list for passing further up the stack.
I might add that from a Functional Programming perspective print is a side affect as it pertains to return.
Consider programming as an extent of mathematics. Your function takes a set of inputs, performs an action on them and returns the computation. Print in this case is not a computation. It causes an interaction with the system's IO to provide output to the user.
As for return and print in a recursive function, return is the only required operation. Recursion requires inputs, an optional computation and a test. The test defines if the function will be called again with the computation modified inputs or if the modified inputs are the final solution to the overall equation. No where in this process is print required, and per Functional purists, it really has no place in a recursive function ( unless its computation IS to print).
The difference between print and return in a recursive function is similar to the difference in an iterative function. Print is direct output to the user and return is the result of the function. You have to return at every step or the function will never end and you will get an error.
For example-
def factorial(n):
if n == 1:
return 1
else:
return n * factorial(n-1)
If you used print instead the function would never end.

Is there a way to decorate/perform operations on every line of a function in Python?

Say I have a function or method that does something repetitive, like checking a value, before performing every operation it does, like so:
def myfunc():
if mybool:
do_operation_1()
else:
return
if mybool:
do_operation_2()
else:
return
...
These checks get repetitive, and end up wasting a lot of time and keyboard springs, especially when they are needed very often.
If you have control over the operation functions, like, do_operation_N you can decorate the functions with something that checks the boolean.
But what if you don't have control over the individual do_operation_N operations? If, for each line in a function or method, I want the same check to be performed, is there some way to "insert" it without explicitly writing it in on each operation line? For example, is there some decorator magic by which I could do the following?
def magic_decorator(to_decorate):
def check(*args, **kwargs):
for call in to_decorate: #magic
if mybool:
to_decorate.do_call(call) #magic
else:
return #or break, raise an exception, etc
return check
#magic_decorator
def myfunc():
do_operation_1()
do_operation_2()
...
If there is a way to achieve this, I don't care if it uses decorators or not; I just want some way to say "for every line in function/method X, do Y first".
The "magic" example of a do_call method above is shorthand for what I'm after, but it would encounter serious problems with out-of-order execution of individual lines (for example, if a function's first line was a variable assignment, and its second was a use of that variable, executing them out of order would cause problems).
To be clear: the ability to externally control the line-by-line order of a function's execution is not what I'm trying to achieve: ideally, I'd just implement something that, in the natural execution order, would perform an operation each time myfunc does something. If "does something" ends up being limited to "calls a function or method" (excluding assignments, if checks, etc), that is fine.
Store your operations in a sequence, then use a loop:
ops = (do_operation_1, do_operation_2, do_operation_3)
for op in ops:
if mybool:
op()
else:
return
Essentially, you can extract the file and line number from the decorated function, go re-read the function, compile it to an AST, insert nodes in the AST, and then compile the AST and use that as the function.
This method can be used for very long functions, which is a problem if you are using the approach above.

Python method that is also a generator function?

I'm trying to build a method that also acts like a generator function, at a flip of a switch (want_gen below).
Something like:
def optimize(x, want_gen):
# ... declaration and validation code
for i in range(100):
# estimate foo, bar, baz
# ... some code here
x = calculate_next_x(x, foo, bar, baz)
if want_gen:
yield x
if not want_gen:
return x
But of course this doesn't work -- Python apparently doesn't allow yield and return in the same method, even though they cannot be executed simultaneously.
The code is quite involved, and refactoring the declaration and validation code doesn't make much sense (too many state variables -- I will end up with difficult-to-name helper routines of 7+ parameters, which is decidedly ugly). And of course, I'd like to avoid code duplication as much as possible.
Is there some code pattern that would make sense here to achieve the behaviour I want?
Why do I need that?
I have a rather complicated and time-consuming optimization routine, and I'd like to get feedback about its current state during runtime (to display in e.g. GUI). The old behaviour needs to be there for backwards compatibility. Multithreading and messaging is too much work for too little additional benefit, especially when cross-platform operation is necessary.
Edit:
Perhaps I should have mentioned that since each optimization step is rather lengthy (there are some numerical simulations involved as well), I'd like to be able to "step in" at a certain iteration and twiddle some parameters, or abort the whole business altogether. The generators seemed like a good idea, since I could launch another iteration at my discretion, fiddling in the meantime with some parameters.
Since all you seem to want is some sort of feedback for a long running function, why not just pass in a reference to a callback procedure that will be called at regular intervals?
An edit to my answer, why not just always yield? You can have a function which yields a single value. If you don't want that then just choose to have your function either return a generator itself or the value:
def stuff(x, want_gen):
if want_gen:
def my_gen(x):
#code with yield
return my_gen
else:
return x
That way you are always returning a value. In Python, functions are objects.
Well...we can always remember that yield was implemented in the language as a way to facilitate the existence of generator objects, but one can always implement them either from scratch, or getting the best of both worlds:
class Optimize(object):
def __init__(self, x):
self.x = x
def __iter__(self):
x = self.x
# ... declaration and validation code
for i in range(100):
# estimate foo, bar, baz
# ... some code here
x = calculate_next_x(x, foo, bar, baz)
yield x
def __call__(self):
gen = iter(self)
return gen.next()
def optimize(x, wantgen):
if wantgen:
return iter(Optimize(x))
else:
return Optimize(x)()
Not that you don't even need the "optimize" function wrapper - I just put it in there so it becomes a drop-in replacement for your example (would it work).
The way the class is declared, you can do simply:
for y in Optimize(x):
#code
to use it as a generator, or:
k = Optimize(x)()
to use it as a function.
Kind of messy, but I think this does the same as your original code was asking:
def optimize(x, want_gen):
def optimize_gen(x):
# ... declaration and validation code
for i in range(100):
# estimate foo, bar, baz
# ... some code here
x = calculate_next_x(x, foo, bar, baz)
if want_gen:
yield x
if want_gen:
return optimize_gen(x)
for x in optimize_gen(x):
pass
return x
Alternatively the for loop at the end could be written:
return list(optimize_gen(x))[-1]
Now ask yourself if you really want to do this. Why do you sometimes want the whole sequence and sometimes only want the last element? Smells a bit fishy to me.
It's not completely clear what you want to happen if you switch between generator and function modes.
But as a first try: perhaps wrap the generator version in a new method which explicitly throws away the intermediate steps?
def gen():
for i in range(100):
yield i
def wrap():
for x in gen():
pass
return x
print "wrap=", wrap()
With this version you could step into gen() by looping over smaller numbers of the range, make adjustments, and then use wrap() only when you want to finish up.
Simplest is to write two methods, one the generator and the other calling the generator and just returning the value. If you really want one function with both possibilities, you can always use the want_gen flag to test what sort of return value, returning the iterator produced by the generator function when True and just the value otherwise.
How about this pattern. Make your 3 line of changes to convert the function to a generator. Rename it to NewFunctionName. Replace the existing function with one that either returns the generator if want_gen is True, or exhausts the generator and returns the final value.

Categories

Resources