Okay, I know you can have a program keep running while a certain condition is true using the while statement. However, is it incorrect or bad practice to just recall the function in the else condition like below?
def ask():
me = input("What is your name? ")
if me == "Tom":
print("Hi, Tom!")
else:
print ("Who are you?")
ask()
It just seems like an easier, shorthand version of the 'while statement' but I haven't really seen a program executed like this in the Python tutorials.
To be totally honest they both "work" it just depends on your user case. Granted you are more likely to hit recursion depth compared to something going wrong with while they both achieve similar results. Really its more simple and in my opinion slightly more pythonic (in this specific case) to use a while loop. (why make it more complicated?)
I wouldn't consider it bad practice unless you expect hundreds to thousands of recursive calls, or if memory management is important for your particular application.
As stated in other answers, Python doesn't support tail recursion elimination, which means that a recursive call to the same function doesn't have to add a new stack frame to the stack. This avoids wasting unnecessary memory.
For an interesting read about why Guido, the creator of Python, considers tail recursion elimination to be unpythonic, see: http://neopythonic.blogspot.com/2009/04/tail-recursion-elimination.html
Shorthand, you say? Compared to:
def ask():
while input("What is your name? ") != "Tom":
print ("Who are you?")
print("Hi, Tom!")
I suggest to use a while statement, because you will feel difficulties when the ask function become to have its upper limit to try to input and return the result value.
To add these functionality, I modify this function such as:
def ask(count):
if count < 0:
return False
me = input("What is your name? ")
if me == "Tom":
print("Hi, Tom!")
return True
else:
print ("Who are you?")
return ask(count - 1)
Is that implementation so complicated and confusing?
If the ask function is implemented using 'while' statement, the modification is more simple.
Just change 'while' to 'for' to set the loop with an upper limit and insert 'return' statement.
Related
Yesterday I posted a question where I was searching for a way to do an infinite for loop, without using while at all (because my teacher wants so, and also, we can't use any commands we haven't seen in class). It was difficult as apparently there wasn't a very viable option that didn't use while, or other functions like itertools or .append, etc.
You can see that question here
Also, thanks a lot for the feedback you guys brought me! :)
But I managed to talk with my teacher and we got permission to use itertools or just a range big enough (instead of actually infinite).
I solved a few exercises already, but now I have the following instructions:
(Think about grades)
• Ask the user a number (through inputs), and keep asking until the user tells to stop.
• Then, calculate the average from all the numbers entered.
(It's actually a little more complex, but I shortened it and I believe I can deal with the rest)
As I said, I must use a for loop, and I can't use whiles at all.
If I could use while, I'd do something like this:
def grades():
totalg = 0
countg = 0
keepAdding = "y"
while(keepAdding == "y"):
qualif = int(input("Insert grades obtained, in scale from 0 to 100 "))
totalg = totalg + qualif
countg = countg + 1
keepAdding = str(input("Do you wish to keep adding data? (y/n) "))
print("The average of your grades is", totalg/countg)
How can I do something like that, but with for loops? I have no idea on how to store the data for later calculation.
Also, I'm interested into knowing a more "proper" way to be able to end the loop, but I can't use a break neither.
Thanks in advance! Any advice is appreciated and welcome! :)
One way to do this is, without outside modules, is to use two-arg iter; when passed two arguments, the first is a no-argument function to call over and over, and the second is a sentinel value than indicates you should stop.
So for example, you could make an infinite loop with something as simple as:
for _ in iter(bool, True):
Since the bool constructor returns False, a sentinel value of True will never occur, so that's an infinite loop.
Similarly, to make a loop that prompts until the user responds with a given sentinel string, like 'q' for quit (or just the empty string), you could do:
for inp in iter(lambda: input("Insert grades obtained, in scale from 0 to 100 (type 'q' to quit)"), 'q'):
val = int(inp)
... rest of loop ...
Obviously, this is a little obscure (two-arg iter is rarely seen), so usually you'd use while True: with the loop containing a test-and-break or test-and-return (the latter doesn't violate the letter of the teacher's requirements). Similarly, exception handling can be used to exit the loop, though it's ugly:
try:
for ...:
if test_for_end:
raise StopIteration
except StopIteration:
pass
# You're outside the loop
Note: Literally everything I've mentioned is terrible style, aside from an actual while True: loop with a test-and-break/return case. But you've got one hand tied behind your back, so I'm suggesting some terrible mutant hands to substitute.
Even though 'no-break' rule and a request for a "proper" way to end a loop are somewhat contradictory, I'd say that is possible, even without return :
grades = [0]
for j in grades:
t = int(raw_input('grade:'))
ans = raw_input('more? [y/n]:').lower()
if(ans == 'y'):
grades.append(t)
else:
grades[0] = t
print(sum(grades)*1.0/len(grades))
here we just iterate over ever-growing list of values, and when we need to stop - we simply stop adding values to it, and the loop ends.
HOWEVER
This is NOT a proper way of handling that issue, read ShadowRanger for more details - this is bad coding style and should not be used.
Maybe saving all the data obtained in an array?
I think arrays on python work as Linked Lists, so you won't have any overflow problems, at least that would be a starting point
I'm fairly experienced with Python, but as I was helping out a friend with a script, I noticed he had solved a common problem in a different way than I was familiar with. He is making sure that the user input is in a valid format (a float); I am used to seeing something like this, which is also what all answers I could find say:
def get_input()
while True:
try:
val = float(input("input pls"))
return val
except:
print("not valid, try again)
He had however solved it using recursion, like this:
def get_input():
try:
val = float(input("input pls"))
return val
except:
print("not valid, try again")
return get_input()
Is there any downside to this?
Some issues or data about this:
There is a recursion limit (very hight, but may surpass)
Each time the get_input method is called recursively its creating a new stack for the scope, even more, it will chain the try...except blocks, this is awful for memory usage and performance.
The recursive method is usually more difficult to debug.
But since it looks like a toy example maybe this just doesnt matter.
I personally would not do that in Python although to me it does look easy to read. The problem with python is that it does not have tail-call optimization where the approach here would be optimised by the compiler as the last thing you are doing is returning the value.
To make this work, you could use a generator based approach so that the number of times a user will get this wrong is independent to whether or not the program can handle it. (This does not look as elegant as the solution you have given but does handle the infinite recursion)
def get_input_from_keyboard():
# I have used raw_input instead of input as I am using python 2.7
return float(raw_input("input pls"))
def try_again():
print("not valid, try again")
for x in get_input():
yield x
def get_input():
try:
yield get_input_from_keyboard()
except ValueError:
for x in try_again():
yield x
list[get_input()][0]
That said, the recursive approach you have provided could be adapted by catching RuntimeError exception but that is very risky as the reason could be that there really is something which has gone wrong apart from a stack overflow.
I am an amateur Python coder learning in school. We recently went over functions and did some work at home. I am confused on the point/meaning of the return statement. Our goal was to simply turn a letter into its ASCII counter part using ord(). My code works as intended however what is the use of the return statement, and how can it be used in this situation to take this function further?
Letter = input("What is your letter? ")
def ordfunction ( x ):
x=ord(x)
print(x)
return[x]
ordfunction(Letter) x
Whenever we write a function it perform some task, on basis of execution it provide some result. Now we have lot of options to use this result.
One we can print/display that result on console. for which we use print to show o/p. Here is use:-
Letter = input("What is your letter? ")
def ordfunction ( x ):
x=ord(x)
print(x)
ordfunction(Letter)
So it will display output on console apart from this it dosn't perform any things. We can use this output to store in a file or send on any device.
Further other way is to use return to provide result of function. Here we can hold this value to use further in any kind of calculation like:-
Letter = input("What is your letter? ")
def ordfunction ( x ):
x=ord(x)
return x
a = ordfunction(Letter)
print (a+100)
So return with provide use result of execution to use it further throughout program.
Further you can refer:-
Why would you use the return statement in Python?
There are basically two things that a method/function can do: change some kind of state or give the caller some kind of information.
For example, if you write something to the console, you've changed something about the system state. This is sometimes called a side effect.
The second thing a method can do is give its caller some kind of information. return is a way to pass data back to the caller - it's the "result" of the method. (In many programming languages, you can also use it to exit a method immediately, but that's a different topic).
Think about a common function: 2 + 3. Most people aren't used to thinking of + as a function, but it is. (If it helps, you can think of this as plus(2, 3)). In this case, the plus function "returns" five - that's the result of the operation, the information you were looking for when you "called" it to begin with.
Hopefully, this clarifies things a little bit - if not please feel free to comment and I can edit.
Quoting definition of a math function:
In mathematics, a function is a relation between a set of inputs and a
set of permissible outputs with the property that each input is
related to exactly one output.
In short, the return is the output. Think about a math function f(x) = x + 100.
x is the input
x + 100 is the implementation of the function
The return is the output of the function, which is the result of x + 100
Equivalent python function:
def f_of_x(x):
result = x + 100
return result
Return is your answer to one statement; example: is it raining? Yes, it's raining
Your answer is returned to your question.
Simple
I also had trouble understanding the difference between return and print. After you return a function you should:
print(ordfunction(Letter))
To see your function. Print is just made for humans to see what is going on. We usually don't need the print function.
I wanna to make my code look nicer.
Example:
result = somefunction()
if result == what_i_need:
do_something()
else:
print 'that\'s not what i need', result
I'm trying to make something like this:
if somefunction() == what_i_need:
do_something()
else:
print 'that\'s not what i need', <return value of somefunction>
Is this possible?
Here's something you could technically try, but shouldn't:
def somefunction():
val = 3 # calculate value
globals()['somefunction_return'] = val # store it in globals() first
return val # return as normal
def do_something():
print 'got it'
what_i_need = 3
if somefunction() == what_i_need:
do_something()
print 'that\'s not what i need', somefunction_return
# result:
#
# got it
# that's not what i need 3
Why shouldn't you do this?
The assignment is still happening somewhere else, so all its done is sweep the unwanted code out of the way. Pay no attention to the garbage behind the curtain.
Messing with globals() is more fragile than a simple assignment done in the way you're already doing it, partly because it's more difficult for the developer to avoid tripping over it.
It introduces something called "side effects," extra events that a function does without saying so. In this example, somefunction is doing something in addition to its planned purpose, without advertising as much. This makes code much harder to maintain.
It makes the code more difficult to read and follow, which goes against the intent of Python. Imagine that someone is reading the if structure above. How are they supposed to know where somefunction_return came from? They would have to look through every line of code until they found the offending side effect in somefunction. We might have even named it something else, like my_foobar_value, and then the reader wouldn't even have a hint that they should check somefunction.
Please continue to use the ordinary assignment you already have in place.
No, the only sensible way to capture a function's return value in Python is to explicitly assign it to a variable.
Even if there was a device for referring to a previous function's return value through implicit means, Python culture abhors this sort of thing. One oft-cited Python principle is "explicit is better than implicit".
This question already has answers here:
It is more efficient to use if-return-return or if-else-return?
(9 answers)
Closed 8 years ago.
I'm getting to this question again from time to time. Is there a general answer on this?
If there is a single if-else construct and the if section has a continue, break or return in it, should it be followed by an else for readability or some reasons?
if v == 0:
continue # / break / return
else: # is this necessary?
...
Semantically, there is no requirement put the ... inside an else clause. Whether or not you do is largely a matter of personal preference.
When I am thinking about how to structure code like this, there are competing considerations. On the one hand, I like to keep the number of nesting levels to a minimum. On the other, I try to use break and continue in moderation, since to my eye they make the flow of control somewhat harder to follow.
For these reasons, I would almost never use the form shown in your question. Instead, I would write either
if v == 0:
continue
# ...
or
if v != 0:
# ...
I would generally prefer the latter to the former. The choice largely depends on how much code there is in the # ... block (which, as a rule of thumb, I would try to keep to a minimum).
It may not be necessary, but it's a good idea in my opinion because
Explicit is better than implicit (The Zen of Python, Tim Peters)
Readability counts (ibid.)
and the indented blocks make it obvious what you want to happen when the condition is True or False.
if foo:
do_this()
break
else:
do_that()
Here, do_this() and do_that() are "on the same level". In my opinion, that looks nicer than
if foo:
do_this()
break
do_that()
Yes.
one:
for readability.
two:
It can help you debug your application. Assume that you have a block of code where the if statement doesn't need an else block and the else block doesn't make any sense and should never be hit.
You can always put a print statement in there or call the error message code to catch possible bad data operations.
I hope this helps.
Edit : I think this depends on the context of the usage where we are using the if-else construct. But however for readability , understandability it is better to use else.