Why is yield "blocking" all other functionality? - python

I decided to finally learn yield to make generators and came across this weird thing:
If I run this code, it prints out <generator ...>. It doesn't print num or stop execution at 3.1...
If I remove the for-yield lines, then it works correctly.
def gen(num = 1):
print(num)
if num == 1:
return 3
if num == 2:
return 3.1
for i in range(num):
yield i
print(gen(2))
Why does this happen?
I'm using Python 3.8.12

Related

Check if a function has been called from a loop

Is it possible to check dynamically whether a function has been called from within a loop?
Example:
def some_function():
if called_from_loop:
print("Hey, I'm called from a loop!")
for i in range(0, 1):
some_function()
some_function()
Expected output:
> Hey, I'm called from a loop!
Not sure if this is going to be 100% reliable. It's also rather cumbersome and would have to be written inside the function of interest rather than in its own discrete function for fairly obvious reasons.
We can get the source code for the currently executing .py file
We can also get a stack trace.
Therefore, we can determine the line number in the code from where our function has been called. Thus we can navigate the source code (backwards) taking care to note indentation and see where the indentation decreases and if the line where that occurs starts with either 'for' or 'while' then we were called from within a loop.
So here's the fun:
import traceback
import inspect
import sys
def getws(s):
return len(s) - len(s.lstrip())
def func():
source = inspect.getsource(sys.modules[__name__]).splitlines()
stack = traceback.extract_stack()
lineno = stack[-2].lineno-1
isLooped = False
if (ws := getws(source[lineno])) > 0:
for i in range(lineno-1, -1, -1):
if (_ws := getws(line := source[i])) < ws:
if (tokens := line.split()) and tokens[0] in {'for', 'while'}:
isLooped = True
break
if (ws := _ws) == 0:
break
print('Called from loop' if isLooped else 'Not from loop')
def looper():
for _ in range(1):
# banana
func()
def looper2(): # this code is nonsense
i = 5
while i > 0:
if i < 10:
func()
break
looper()
looper2()
func()
while True:
func()
break
if __name__ == '__main__':
func()
Output:
Called from loop
Called from loop
Not from loop
Called from loop
Not from loop

Why can the return keyword be omitted in some Python functions?

I am new to Python and want to understand why there is no use of return in the following code, and still it is working perfectly fine.
def printCount(num):
for i in range(2, num +1):
print(i)
printCount(10)
If you don't use the return statement in your function definition, the implicit statement
return None
is appended to the function body.
It means that your code
def printCount(num):
for i in range(2, num +1):
print(i)
printCount(10)
is fully equivalent to the code
def printCount(num):
for i in range(2, num +1):
print(i)
return None
printCount(10)
In python return stops the function, and sends the returned value back. For example:
def printCount(num):
for i in range(2, num +1):
return(i) #THIS IS USING RETURN
printCount(10)
count = printCount(5)
In this code, on the first iteration in the for loop, it would return i, which would be 2. This would stop the function and set the variable count to the returned value, which is 2. The function wouldn't do anything else.
In your code, I pressume that return is not used because the desired output is:
2
3
4
5...
If you used return, the code would send back 2 at the beginning and that would be it.

Recursion program flow

I have some textbook code that calls itself recursively. I don't understand the program flow. Here is the code:
def Recur_Factorial_Data(DataArray):
numbers = list(DataArray)
num_counter = 0
list_of_results = []
for num_float in numbers:
n = int(num_float)
1. result = Recur_Factorial(n)
list_of_results.append(result)
def Recur_Factorial(num):
if num == 1:
2. return num
else:
result = num*Recur_Factorial(num-1)
3. return result
if num < 0:
return -1
elif num == 0:
return 0
else:
return 0
In Recur_Factorial_Data, I loop through the data elements and call Recur_Factorial, which returns its value back to the calling function (Recur_Factorial_Data). I would expect that the lines marked 2 ("return num") and 3 ("return result") would always return a value back to the calling function, but that's not the case. For example, where the initial value (from the array DataArray) is 11, the function repeatedly calls itself until num is 1; at that point, the program falls to the line marked 2, but it does not loop back to the line marked 1. Instead, it falls through to the next line. The same happened on the line marked 3 -- I would expect it to return the result back to the calling function, but it does that in some cases and not in others.
I hope this is enough description to understand my question -- I just don't know why each return does not loop back to return the result to the calling function.
EDIT: The question at Understanding how recursive functions work is very helpful, and I recommend it to anyone interested in recursion. My question here is a bit different -- I asked it in the context of the program flow of the Python code where the recursive function is called.
If it call itself recursively 10 times, it will be at the 10th level of recursion and should go back 10 times at the point where there was a recursive call with an intermediate result and only then exit from the recursive function to the place where it was called. Learn more about recursion
Also try to rearrange instructions in Recur_Factorial function in this way:
def Recur_Factorial(num):
if num < 0:
return -1
elif num == 0:
return 0
elif num == 1:
return num
else:
return num * Recur_Factorial(num-1)

How to run and check this code? (Python basics)

Basically, my question is about how to run this code? Finding the second smallest number from the given list using divide-and-conquer. I tried with print..But it gives me nothing. Just wanna see how this code works. Sorry for simple question, totally New in Python.
Well, just use a function call to run it, and a print to print it:
def two_min(arr):
n = len(arr)
if n==2: # Oops, we don't consider this as comparison, right?
if arr[0]<arr[1]: # Line 1
return (arr[0], arr[1])
else:
return (arr[1], arr[0])
(least_left, sec_least_left) = two_min(arr[0:n/2])
(least_right, sec_least_right) = two_min(arr[n/2:])
if least_left < least_right: # Line 2
least = least_left
if least_right < sec_least_left: # Line 3
return (least, least_right)
else:
return (least, sec_least_left)
else:
least = least_right
if least_left < sec_least_right: # Line 4
return (least, least_left)
else:
return (least, sec_least_right)
print two_main([12,2])
If you'd like to know how this works, you can take a look at the online python visualizer. Link.

why won't this python program start?

I copied the source code of a python program written by someone else on a tutorial forum and I have made a few modifications to it to match my own needs
the original was meant to run in the python shell i believe and i got it to run in the shell but I need to save it to python IDLE and run it from there
I am using python 3.2.3 IDLE btw
this is what I have written:
def fibonacci(previous=0,current=1):
n = int(input("Calculate fibonacci sequence value up to: "))
if previous > current:
previous,current = current, previous
yield previous
yield current
while True:
current,previous = previous+current,current
yield current
x = fibonacci()
for i in range(n):
print(next(x))
fibonacci()
it doesn't run, like no errors pop up i just get the arrows: >>
that's it nothing happens.
The program does start and runs through. Unfortunately, by using yield in the function, you make it a generator, and the generator gets only constructed in the last line, but never evaluated.
Instead, you want to outdent the last four lines:
def fibonacci(previous=0,current=1):
if previous > current:
previous,current = current, previous
yield previous
yield current
while True:
current,previous = previous+current,current
yield current
n = int(input("Calculate fibonacci sequence value up to: "))
x = fibonacci()
for i in range(n):
print(next(x))

Categories