Function that to exit from other function - python-3.x

I wanted to create to a function which, when called in other function it exits the previous function based on the first function's input.
def function_2(checking):
if checking == 'cancel':
# I wanted to exit from the function_1
def function_1():
the_input = input("Enter the text: ")
function_2(the_input)
I wanted the code for the function_2 so that it exits from function_1, I know that I can put the if statement in function_1 itself but ill use this to check more than one in input in the same function or even in different function I cant put the if block everywhere it will look unorganized so i want to create a function and it will be convenient to check for more than one word like if cancel is entered i wanted to exit the programm if hello is entered i wanted to do something, to do something its ok but to exit from the current function with the help of other function code please :) if any doubts ask in the comment ill try to give you more info im using python 3.x.x on Windows8.

Why not simply:
def should_continue(checking):
if checking == 'cancel':
return False
return True
def function_1():
the_input = input("Enter the text: ")
if not should_continue(the_input):
return
This is the best solution I think.
Another alternative is to raise an Exception, for example:
def function_2(checking):
if checking == 'cancel':
raise KeyboardInterrupt
def function_1():
the_input = input("Enter the text: ")
function_2(the_input)
try:
function_1()
except KeyboardInterrupt:
print("cancelled by user")

Related

Functions that include input/print

I'm writing a program where you can play blackjack with a computer. I've implemented a class, a "main" and a bunch of others functions. The problem is that almost all of my them are build to get the proper input from the user. For instance:
def get_the_answer():
while True:
answer = input("Write 'reveal' to reveal cards, 'add' to add one more: ")
if answer in ['reveal', 'add']:
break
else:
continue
return answer
Or this one, which also has some prints in it:
def start_and_greet():
print('', colored('Hi! Shall we play Blackjack?', 'yellow'), '', sep='\n')
print(colored(blackjack()))
print()
while True:
answer = input("Write 'start' / 'exit': ")
if answer in ['start', 'exit']:
break
else:
continue
return answer
If I put all my inputs and prints in "main" function, there will be almost no additional functions besides "main", so this won't be acceptable by the task.
The main reason why I'm worrying about it is that I don't understand how one should test this...
Thank you in advance for your help!
I know that it is not recommended to use a function with print / input, although I saw how David Malan (CS50P course) uses the similar one in lectures:
def get_number():
while True:
n = int(input("What's n? "))
if n > 0:
break
return n

Require user input until is correct [duplicate]

This question already has answers here:
Asking the user for input until they give a valid response
(22 answers)
Closed 2 years ago.
What is the best way of repeatedly asking for the user for correct input?
For example I'd like to continue checking if the a value is an int or not and when it is finally say ok you picked number.
I'm stuck here:
try:
a = int(input())
except:
print("incorrect pick a number and try again")
#Somewhere here
print("Ok thanks you finally picked a number")
The only exception you want to catch is the ValueError raised by int should it not be able to convert its argument to an integer. The try statement will be in a loop that you will explicitly break out of if you don't get an exception.
while True:
response = input()
try:
a = int(response)
except ValueError:
print("incorrect pick a number and try again")
else:
print("Ok thanks you finally picked a number")
break
if you want/must mantain this code, i think the unique way is using a loop.
while True:
try:
a = int(input('Insert a number:'))
print ('Your number is {}'.format(a))
break
except ValueError:
print("incorrect pick a number and try again")
So if the user inserts an integer, the code prints number and break the loop else repeats the request.
I hope it's useful for you!
You can do it like this:
a = None
while type(a) != int:
try:
a = int(input())
except:
print("incorrect pick a number and try again")
print("Ok thanks you finally picked a number")
Essentially:
Create a variable with NoneType so when you first run the program it can access the while loop because the conditions meats.
Loop until the type of that variable is not int.
Request the user input and try to cast as integer, if it fails print an error and try again.
When the input is of integer type it exit the loop and print the final message.
You can use type() or isinstance() to check, but as suggested by #chepner avoid the usage of type because it simply returns the type of an object whereas, isinstance() returns true if the object argument is an instance of the classinfo argument, or of a (direct, indirect or virtual) subclass thereof.
To help you understand:
class foo:
pass
class bar(foo):
pass
isinstance(foo(), foo) # returns True
type(foo()) == foo # returns True
isinstance(bar(), foo) # returns True
type(bar()) == foo # returns False,and this probably won't be what you want.
In the case you want to use isinstance() the code will result as:
a = None
while not isinstance(a, int):
try:
a = int(input())
except:
print("incorrect pick a number and try again")
print("Ok thanks you finally picked a number")
As pointed out by #L3viathan you can also do:
a = None
while a is None:
try:
a = int(input())
except:
print("incorrect pick a number and try again")
print("Ok thanks you finally picked a number")
In this case you loop until a get a value, that will be done only if the exception is not thrown.
while True:
try:
number=int(input("Enter a number: "))
except:
print("incorrect pick a number and try again")
else:
print("ok Thanks you finally picked a number ")
break

Unittesting for correct 'continue' behaviour

I have a function that asks a user for confirmation via a prompt. It accepts y or n as answers, otherwise it asks again.
Now, I want to write a unittest for this function. I can test the correct behaviour for y or n just fine, but how do I test that my function correctly rejects inacceptable input?
Here's the code for foo.py:
def get_input(text):
"""gets console input and returns it; needed for mocking during unittest
"""
return input(text)
def confirm(message='Confirm?', default=False):
"""prompts for yes or no response from the user. Returns True for yes and
False for no.
'default' should be set to the default value assumed by the caller when
user simply types ENTER, and is marked in the prompt with square brackets.
"""
if default:
message = '%s [y]|n: ' % (message) # default answer = yes
else:
message = '%s y|[n]: ' % (message) # default answer = no
while True:
answer = get_input(message).lower()
if not answer:
return default
if answer not in ['y', 'n']:
print('Please enter y or n!')
continue
if answer == "y":
return True
if answer == 'n':
return False
answer = confirm()
print(answer)
And here is my Test class:
import unittest
import foo
class TestFoo_confirm(unittest.TestCase):
"""testing confirm function
"""
#unittest.mock.patch('foo.get_input', return_value='y')
def test_answer_yes(self, _):
self.assertEqual(foo.confirm(), True) # confirmed if 'y' was entered
So, how do I write a similar test for an input-value like '1' (or how do I need to adjust my confirm() function to make it testeable)?
Currently, if I call foo.confirm() from the unittest file, it just gets stuck in an infinite loop and it doesn't return anything. (I understand why this is happening, just not how to circumvent it.)
Any ideas?
You could try this:
import unittest, unittest.mock
import foo
class TestFoo_confirm(unittest.TestCase):
"""testing confirm function
"""
#unittest.mock.patch('foo.get_input', return_value='y')
def test_answer_yes(self, _):
self.assertEqual(foo.confirm(), True) # confirmed if 'y' was entered
#unittest.mock.patch('builtins.print')
#unittest.mock.patch('foo.get_input', side_effect=['1','yn','yes','y']) # this will make the mock return '1', 'yn' and so on in sequence
def test_invalid_answer(self, mock_input, mock_print):
self.assertEqual(foo.confirm(), True) # it should eventually return True
self.assertEqual(mock_input.call_count, 4) # input should be called four times
mock_print.assert_called_with('Please enter y or n!')
In the second test case, we imitate a user who enters three invalid inputs, and, after being prompted again, finally enters 'y'. So we patch foo.get_input in such a way that it returns 1 the first time it's called, then yn, then yes and finally y. The first three examples should cause the confirm function to prompt the user again. I also patched the print function, so that the 'Please enter y or n!' message wouldn't show up when testing. This isn't necessary.
Then we assert that our mock input was called four times, meaning that the first three times, the confirm function reprompted.
Finally we assert that the print function was called (at least once) with 'Please enter y or n!'.
This does not test if the correct number of print statements were made or if they were in correct order, but I suspect this would be possible too

defining a function in python 3

the moment you guess the correct number, it freezes and doesn't proceed further, however if I don't define the function do_guess_round and instead simply write the code after the second while True statement it works perfectly. I guess I am incorrectly defining the function
import random
computers_number = random.randint(1,100)
prompt=('what is your guess? ')
def do_guess_round():
"""choose a random number, prompt the user to guess it
check whether the user is true,
and repeat the pocess untill the user is correct"""
while True:
players_guess=input (prompt)
if computers_number == int(players_guess):
print ('correct! well done')
break
elif computers_number<int(players_guess):
print ("incorrect, your guess is higher")
else:
print ('incorrect, your guess is lower')
print ("Starting a new round ")
print ("let the guessing game begin")
while True:
do_guess_round()
Current your do_guess_round() function does not do anything. You need to indent the code that is supposed to be contained in it. The while True beneath it is not indented, so the body of the function currently only consists of the string:
"""choose a random number, prompt the user to guess it
check whether the user is true,
and repeat the pocess untill the user is correct"""
At the moment you guess the correct number, your code collapses to
def do_guess_round():
while True:
break
while True:
do_guess_round()
No surprise it freezes, you haven't built any way for it to quit - break only leaves one level of loop. Presumably you're going to move the code to generate numbers into the function? You need something more like
def do_guess_round():
# read player guess here
if guess matches:
return True
else:
return False
result = False
while result != True:
result = do_guess_round()
def do_guess_round():
"""choose a random number, prompt the user to guess it
check whether the user is true,
and repeat the pocess untill the user is correct"""
while True:
The "while True" loop isn't indented, so it isn't in the function, indent the loop an it's contents, then you should be fine.

how to pass many arguments through a command function (do_)

I want to code a simple command that could take 3 arguments for a text adventure game.
Basically at the prompt, I would type 'use key unlock door' and it would run a particular block.
Here is what I coded but it does not work:
def do_use(self, tool, action, object):
if tool == 'key':
if action == 'unlock':
if object == 'door':
print("seems like it works!")
else:
print("nope 1")
else:
print("nope 2")
else:
print("nope 3")
Notes: the rest of the commands work fine. I imported cmd
and the following is the main code:
class Game(cmd.Cmd):
def __init__(self):
cmd.Cmd.__init__(self)
....
if __name__ == "__main__":
g = Game()
g.cmdloop()
At the prompt, when I type:
>>> use key unlock door
I get the following error message:
TypeError: do_use() takes exactly 4 arguments (2 given)
The code would work if it would print:
seems like it works!
Any help will be appreciated.
Reading that documentation, it looks like all of the commands just take in a single string, and you have to parse the string yourself. Your command is defined as taking 4 arguments (including self), and cmd is calling it with self, input, which is 2. I think could get the result you want with the following:
def do_use(self, user_input):
args = user_input.split()
if len(args) != 3:
print "*** invalid number of arguments"
else:
tool, action, obj = args
# Do the rest of your code here

Resources