Print function calling functions together - python

I was testing with something and I wrote this code for example purposes.I felt the output I got was weird.I expected that function calls are executed one after the other but according to this code both the print statements are getting executed after each other and then the return values are printed together.What does this mean and what is the flow of the code in this case?
global num
num=5
def demo(num):
num+=1
print("hi")
return(num)
print(demo(num),demo(num))
output-
hi
hi
6 6

I expected that function calls are executed one after the other
That's exactly what happens.
But there's no way the print can happen before the demo calls, because it's trying to print out the values returned by those calls. (You can loosely think of this as a special case of anywhere you see parentheses: 2 * (3+4) can't multiply by 2 until it's added 3+4, and print(demo(num), demo(num)) can't print the results of demo(num) and demo(num) until it's called them. But don't take that too literally.)
So, those demo calls happen left to right, then the print call happens.
In more detail, let's step through how it evaluates this line:
print(demo(num),demo(num))
… Python has to do this:
Evaluate print by looking it up as a builtin name, which finds the builtin print function.
Evaluate the first argument.
Evaluate demo by looking it up as a global name, which finds the global demo function that you defined.
Evaluate num by looking it up as a global name, which finds the global 5 value.
Call the function on the argument.
The parameter num gets the value passed in, 5.
num += 1 updates the local variable (parameters are local variables) num to 6.
print("hi") prints out hi.
return(num) returns the value of the local variable, 6.
Evaluate the second argument.
… same as above, it prints out hi and returns 6.
Call the function returned by evaluating print on the two arguments returned by the two calls, so it prints out 6 6.
If you want the rigorous definition, he details are covered in Calls in the reference documentation. In particular (stripping out irrelevant bits)
call ::= primary "(" [argument_list] ")"
 …
The primary must evaluate to a callable object…. All argument expressions are evaluated before the call is attempted.
according to this code both the print statements are getting executed after each other and then the return values are printed together
Yes. The two function calls have to be executed in order, so that it can get the values to pass to the print function. Executing them prints out Hi twice. Then it has all the values, so it can print them, which prints out 6 6, since both values are 6.

Program evaluation has an order of operations just like arithmetic does. And similarly, it's not always intuitive, especially when we "consume" things left to right, up to down while reading.
So, what gives? Lets become the python interpreter and see why order of operations is important.
# A wild statement appears. Time to compute!
print(demo(num),demo(num))
# I cant't print yet! i'm missing info!
I need to evaluate this first demo(num), and by default im going to do it a closed room away from globals
# evaluating demo(num=5) - num here is a new local variable, it has no relation to the global one defined above
num+=1 # num = 6
print("hi") # [[[PRINT hi]]] ~> to console
return 6 # returns the value 6 filling in another piece of the puzzle
Where are we at now? Almost ready to call this print, just need to do this demo thing again
print(6, demo(num))
# What is num though?
# Well, the only num I know of out here in global space is 5
print(6, demo(5))
# evaluate: demo(5)
This seems familiar!
# evaluating: demo(num=5) - again, a NEW local variable is created just for this function call
num+=1 # num = 6
print("hi") # [[[PRINT hi]]] ~> to console
return 6
Finally, print has all its arguments it needs
print(6, 6) # [[[PRINT 6 6]]] ~> to console
print is not magic, it's just another function! Same as the demo you wrote.
And functions will not evaluate until all their parameters are supplied.
print(a, b) needs the values of a & b before it can do its thing.

Related

Can somebody explain me this recursion?

def name(n):
if n>0:
name(n-1)
name(n-1)
print(n)
name(5)
How this is generating 1,1,2,1,1,2,3.....so on output? like which function is working first or both working simultaneously and how n is printing like this.
Try with smaller numbers. For example if you run name(1) it will just print 1. becase two functions in the middle will just return. If you write name(2) it will run the first inner funtion, which will print 1(like I said previously). Second function will do the same and last statement will print 2. So the output is 1 1 2. If you go for name(3) it will just the same as name(2) but twice and will print 3 at the end (1 1 2) (1 1 2) 3. name(4) will do name(3) twice and print 4 at end and so on
Another way to lok at this is in reverse. eg. you look at the smallest number:
name(0): Prints nothing, thus ""
name(1): calls name(0) twice, and then prints 1, thus "1"
name(2): calls name(1) twice, and then prints 2, thus "112"
name(3): calls name(2) twice before it prints 3, thus "1121123"
name(4): calls name(3) twice before it prints 4, thus "112112311211234"
name(5): calls name(4) twice before it prints 5, thus "1121123112112341121123112112345"
Finally the clue is that there is no spcial treatment of functions that recurse. Every call to a function, even print, will wait for that to return and then continue on the next line as long as the statement didn't include a return in which it would return. that name(5) ends up calling itself with different versions of n at different levels is no problem because each of them has their own version of n that is unique to that call.
Hello I attached this image that shows explanation in details

Why does Python print a value in the body of a loop when I don't use print?

I understand that the Python interpreter is a REPL... but in a loop, the "value" of the loop must be single-valued... correct? And yet I see this (tested in both Python 2.7.18 and 3.8.5 with range instead of xrange):
>>> for _ in xrange(5):
... 3
...
3
3
3
3
3
Where is this behavior documented in Python?
It seems to get suppressed when in a called function:
>>> def foo(x):
... 1
... x
... return x+1
...
>>> foo(5)
6
>>> def bar(n):
... for x in xrange(5):
... 1
... x
... return n+1
...
>>> bar(5)
6
>>> for x in xrange(5):
... 1
... x
...
1
0
1
1
1
2
1
3
1
4
Note to downvoters: This is not an obvious behavior! Contrast with Javascript:
> for (var i = 0; i < 5; ++i) {
i
}
4
It's not the "value" of the loop that's resulting in 3 being displayed. It's the result of the interpreter evaluating 3.__repr__() on each iteration of the loop.
For instance if you instead evaluated i you would get the following.
for i in range(5):
i
# 0
# 1
# 2
# 3
# 4
If you want a for loop that doesn't display anything you'll want to make sure that all statements in the loop don't print anything when evaluated in the interpreter. An example of such a statement would be.
for i in range(5):
_ = None
The reason that for loops don't have a "final value" (unlike your javascript example) is because in Python for loops are statements, and statements in Python don't have a value.
The interpreter will print out any variables you just type out ..
It's just a convenience function.
If you type in "3" in the interpreter, it will also print out "3".
You're confusing levels of abstraction. Every statement has its value. In the case of your loop, you interpret the line 3 five times, and thus have five non-empty results returned. The interactive interpreter prints that value each time.
To see it a little more clearly, change the expression:
for i in range(5):
i
Evidently the REPL shows the result of every expression executed as a statement, not just the outer statement (the for-loop). The for-loop itself does not have any value at all: it is just a statement, not an expression.
Incidentally, you can see the same thing in other constructions, such as an if-statement:
if True:
1 + 2
"Hello"
shows
3
'Hello'
in the REPL.
Presumably the reason it does not do the same thing for expressions inside functions is that it would produce so much extraneous information that it would only cause confusion.
Its because you are using Python interactive interpreter (REPL). REPL always calls the repr method of the object. In your case it is 3.
If you try creating a .py file of this code and run it. Nothing will be printed and the program will just run and close.
OK I think I found something definitive in the Python docs under expression statements:
6.1. Expression statements
Expression statements are used (mostly interactively) to compute and write a value, or (usually) to call a procedure (a function that returns no meaningful result; in Python, procedures return the value None). Other uses of expression statements are allowed and occasionally useful. The syntax for an expression statement is:
expression_stmt ::= expression_list
An expression statement evaluates the expression list (which may be a single expression).
In interactive mode, if the value is not None, it is converted to a string using the built-in repr() function and the resulting string is written to standard output (see section The print statement) on a line by itself. (Expression statements yielding None are not written, so that procedure calls do not cause any output.)

Why my return statement is not showing any output?

I was trying to solve the following problem: Draw a star pattern that increases in every step (1st step: 1 star, 2nd step: 2 stars). E.g.
*
**
I am not sure why my code is not showing any output when I am writing return? When I am writing print, it is giving me the star output but also giving me None. May I know why return or print are not working properly? I am using Python 3.7. My code is:
def string(inp):
for i in range (inp):
return i*"*"
print (string(5))
range starts at 0, and return terminates a function, so that means string will always return an empty string.
Here's one possible option for getting your expected result:
def stars(n):
for i in range(1, n+1): # Add one to start and stop
print(i * "*") # Print inside the function
stars(2) # Don't print outside the function
Output:
*
**
If you need to print outside the function, you could use a generator:
def stars(n):
for i in range(1, n+1):
yield i * "*" # "yield" is like "return" but can be used more than once
for s in stars(2):
print(s) # Print each string that gets yielded
# Or print all at once, using the "splat" unpacking operator
print(*stars(5), sep='\n')
Using return won't print an output, use something like this:
def string(inp):
for i in range (inp):
print(i*"*")
string(5)
also this will only print 4, if you make it
for i in range(inp + 1):
It will work as intended,
hope this helps!
I will translate the code to plain English, as explicitly as I can:
Here are the rules that take a value `inp` and compute the `string` of that `inp`:
Letting `i` take on each integer value from 0 up to but not including `inp`:
We are done. The `string` of `inp` is equal to the string '*' repeated `i` times.
Compute the `string` of `5` and display it.
Hopefully the problem is evident: we can only be done with a task once, and i is equal to 0 at that point, so our computed value is an empty string.
When I am writing print, it is giving me the star output but also giving me None
From the described behaviour, I assume that you mean that you tried to replace the word return in your code with print, giving:
def string(inp):
for i in range (inp):
print(i*"*")
print (string(5))
That produces the triangle, of course, except that
Since i will be equal to 0 the first time through the loop, a blank line is printed; and since i will be equal to 4 the last time through the loop, there is no ***** line.
At the end, None is printed, as you describe. This happens because the value computed by string is the special value None, which is then printed because you asked for it to be printed (print(string(5))).
In Python, each call to a function will return a value when it returns, whether or not you use return and whether or not you specify a value to return. The default is this special None value, which is a unique object of its own type. It displays with the text None when printed, but is different from a string with that text (in the same way that the integer 5 is different from the string "5").
May I know why return or print are not working properly?
They are working exactly as designed. return specifies the result of calling the function, and can only happen once per function, and does not cause anything to be displayed. print displays what it is given.
If you wish to return multiple values from a call, then you need to work around that restriction - either by using a generator instead (as in #MadPhysicist's or #wjandrea's answers), or by using some single, structured datum that contains all those values (for example, a list, or a tuple).
A a re-entrant function that preserves state between calls is a generator. To make a generator function, change the keyword return to yield:
def string(n):
for i in range(n):
yield (i + 1) * '*'
Calling this version of string will return a generator that yields a new line of your desired output at each iteration.
To print:
for line in string(5):
print(line)
To print all at once:
print('\n'.join(string(5)))

Why do I not have to define the variable in a for loop using range(), but I do have to in a while loop in Python?

I have the following code using a for loop:
total = 0
for num in range(101):
total = total + num
print(total)
Now the same result using a while loop:
num = 0
total = 0
while num <= 99:
num = num + 1
total = total + num
print(total)
Why is it that I do not have to define num in the first case, but I do have to define it in the second? Are they both not variables?
Well, for is a special statement that automatically defines the variable for you. It would be redundant to require you to declare the variable in advance.
while is a general purpose loop construct. The condition for a while statement doesn't even have to include a variable; for example
while True:
or
while my_function() > 0:
I'd like to approach this question from a slightly different perspective.
If we look at the official Python grammar specification, we can see that (approximately speaking), a while statement takes a test, while a for statement takes an exprlist and testlist.
Conceptually, then, we can understand that a while statement needs one thing: an expression that it can repeatedly evaluate.
On the other hand, a for statement needs two: a collection of expressions to be evaluated, as well as a number of names to bind the results of those evaluations to.
With this in mind, it makes sense that a while statement would not automatically create a temporary variable, since it can accept literals too. Conversely, a for statement must bind to some names.
(Strictly speaking, it is valid, in terms of Python grammar, to put a literal where you would expect a name in a for statement, but contextually that wouldn't make sense, so the language prohibits it.)
In python there is no need, in most cases, to define/declare variables.
The rule is that if you write (assign) a variable then the variable is a local variable of the function; if you only read it instead then it's a global.
Variables assigned at top-level (outside any function) are global... so for example:
x = 12 # this is an assignment, and because we're outside functions x
# is deduced to be a global
def foo():
print(x) # we only "read" x, thus we're talking of the global
def bar():
x = 3 # this is an assignment inside a function, so x is local
print(x) # will print 3, not touching the global
def baz():
x += 3 # this will generate an error: we're writing so it's a
# local, but no value has been ever assigned to it so it
# has "no value" and we cannot "increment" it
def baz2():
global x # this is a declaration, even if we write in the code
# x refers to the global
x += 3 # Now fine... will increment the global
The for statement is simply a loop that writes to a variable: if no declaration is present then the variable will be assumed to be a local; if there is a global or nonlocal declaration then the variable used will have the corresponding scope (nonlocal is used to write to local variable of the enclosing function from code in a nested function: it's not used very frequently in Python).
If you are coming from other programming languages like C, C++ or Java then do not confuse with for in loop of python.
In python, for in loop pick one item from list of items and does something with help of the picked item.
For Loop iterates each element from the list until the given range. So no need of any variable to check condition.
While Loop iterates until the given condition is true. Here we need some variable or value to check the condition, So the variable num is used before the loop.
Python for loops assign the variable and let you use it. We can transform a for loop into a while loop to understand how Python actually does it (hint: it uses iterables!):
iterator = iter(iterable) # fresh new iterator object
done = False
while not done:
try:
item = next(iterator)
except StopIteration:
done = True
else:
# inside code of a for loop, we can use `item` here
pass

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

Categories