unexpected "None" in list - python

i wanted to make a game where you guess the letter. and add a function that will show you all you incorrect guesses, so i made the list:
incorrectguesses = []
and then i made it so it asks the user to guess the letter:
while True:
guess = input("what do you think the letter is?? ")
if guess == secret_letter:
print("you guessed it!")
break
else:
incorrectguesses += [guess]
and you can see that i added the guess to the list if it was wrong.
then, i added a function to print out every item in the given list:
def print_all_items(list_):
for x in list_:
print(x)
and then i ran the function at the end of the loop:
print(print_all_items(incorrectguesses))
but this was the result:
what do you think the letter is?? a
a
None
what do you think the letter is?? b
a
b
None
as you can see, it adds "None" to the end of the list.
thanks if you could help me

print(print_all_items(incorrectguesses))
You're printing the result of the print_all_items() function.
However, that function has no return statement, so it returns None by default.
So, the result of the function is None, and that gets printed.
Since the function itself prints the results, I think you actually just want to call the function, not print its result.

As someone else pointed earlier (beat me to it), it's because you are printing a function that has no return. (In depth explanation a the end).
while True:
guess = input("what do you think the letter is?? ")
if guess == secret_letter:
print("you guessed it!")
break
else:
incorrectguesses += [guess]
print_all_items(incorrectguesses) # ←
You want to call the function, not print it.
That way the function is being run, and prints the elements of incorrectguesses.
Explanation
When you do print(<something>), the print() function is waiting for a value to be returned.
In this case because the <something> is a function, Python runs that function "inside" the print(). When your function print_all_items() is being run, it prints all the elements of the list. Once print_all_items() has finished running, and printed everything, the function doesn't return a value, so it defaults to None. Therefore, the value of the <something> the print(<something>) was waiting for is gets assigned a None value.
I hope I could help!

Related

Why does my code keep on looping like this when I'm using functions?

So I'm trying to make a Hangman console game and im trying to check how many tries I have left and then later add a game over function if tries left. One part of it is working the stringcount function is working properly until I have to call the goAgain function, I'll explain the issue lower in the document
import time
hangmanSolved = "What 'eva hh"
chosingletter = input("Input a letter you would like to try! ")
def goAgain(defaultTries):
defaultTries -= 1
print("Head drawn!", defaultTries, "tries left ")
stringcount()
# if a letter is in, and how many letters are in
def stringcount():
count = 0
lettersIn = hangmanSolved.count(chosingletter)
for i in hangmanSolved:
if i == chosingletter:
count = count + 1
if not count:
print("There are no ", chosingletter, "'s in this sentence! ")
time.sleep(1)
goAgain(defaultTries=5)
elif count == 1:
print("There is only one ", chosingletter, " in this sentence! ")
else:
print("There is ", lettersIn, chosingletter, "'s in this sentence! ")
stringcount()
When I run the code and guess a wrong letter, or rather when I have to call goAgain function it keeps on looping me this output:
Input a letter you would like to try! j
There are no j 's in this sentence!
Head drawn! 4 tries left
There are no j 's in this sentence!
Head drawn! 4 tries left
How can I fix this looping, and the tries counter?!?
So first of all the counter is wrong because you are using a local variable. When the method is called with defaultTries = 5 it will always start at 5 even though you have done defaultTries -= 1.
To fix this you need to read up and assign a global variable outside of the scope so that whenever the user is wrong that global variable gets subtracted.
Furthermore, I am unsure as to why you would use the time module here. What is your goal by doing this?
What you are trying to do is loop through the sentence and check if the letter the user inputs exists inside the sentence. There are easier ways to go about this.
You can use string.indexOf('a'). where 'a' you can change it to the letter you are searching for (the user's input). It returns the index of the first occurrence of the character in the character sequence represented by this object, or -1 if the character does not occur.
I would start with changing those things first!
Every time you call goAgain you call it with defaultTries set to 5. Then, in that function, it subtracts one, leaving you with 4. Then it calls stringount which again calls goAgain which will call stringcount and so on. There's nothing that breaks out of the loop.
So you need to change three things:
Don't pass in the same value of defaultTries every time you call goAgain. You want to allow that variable to decrease.
Git rid of the goAgain function. Instead put that logic in stringcount itself.
Check the value of the number of tries remaining and if it's zero, print out some kind of message, but don't call stringcount in that branch.
def stringcount(tries = 5):
count = 0
tries =- 1
if tries == 0:
print("No tries remaining")
else:
lettersIn = hangmanSolved.count(chosingletter)
for i in hangmanSolved:
if i == chosingletter:
count = count + 1
if not count:
print("There are no ", chosingletter, "'s in this sentence! ")
time.sleep(1)
stringcount(tries)
elif count == 1:
print("There is only one ", chosingletter, " in this sentence! ")
else:
print("There is ", lettersIn, chosingletter, "'s in this sentence! ")
stringcount()
A few other things you can consider changing:
The standard formatting in Python is PEP8 and you should review those. For example, Python convention is to use snake_case instead of camelCase. So you would use something like default_tries instead of defaultTries for example.
It's probably more explicit to check if count == 0 than it is to check if not count.
I think you don't need the loop that updates the variable count. Just use lettersIn (which you should rename as letters_in or, better, just call this count). Now you also don't need to set count==0 at the top of the function.
You're having problems because you are basically using a recursive strategy but you haven't defined a base case, and also because you reinitialize your defaultTries variable to 5 every time you call the goAgain() function. A base case is a condition where you tell a recursive function to stop. In this case tries needs to be 0. Here's an example of what your code might look like:
def goAgain(tries):
tries -= 1
if tries==0:
print("You lose")
return None
print("Head drawn!", tries, "tries left ")
stringcount(tries)
def stringcount(defaultTries=5): #This is how you set default args
chosingletter = input("Input a letter you would like to try! ")
count = 0
lettersIn = hangmanSolved.count(chosingletter)
for i in hangmanSolved:
if i == chosingletter:
count = count + 1
if not count:
print("There are no ", chosingletter, "'s in this sentence! ")
time.sleep(1)
goAgain(defaultTries)
It's up to you whether you want to keep goAgain() and stringcount() separate. I think it makes sense to keep them separate because I can imagine you want to check how many tries are in goAgain and then print new statements accordingly, like "left arm drawn!" etc.

[Random String Generator]Getting stuck in a loop on else condition

So (as you will probably see from my code) I am a beginner at Python (version 3.8.3) and enjoying it very much so far, and I have challenged myself on several different beginner projects. I am currently making a random string generator (i.e. a password generator, hence the use of the secrets module).
# Password Generator
import secrets, string
print("Welcome to the generator. Please specify your requirements")
print("A. All Characters;\nB. No Numbers;\nC. No Punctuation\nPlease choose the appropriate letter for your needs.")
userInput = input()
def userWelcome():
if userInput.lower() == "a":
generatePass = string.ascii_letters + string.digits + string.punctuation
print("How long do you want your string to be?")
stringRange = int(input())
print( "".join(secrets.choice(generatePass) for _ in range(stringRange)) )
elif userInput.lower() == "b":
generatePass = string.ascii_letters + string.punctuation
print("How long do you want your string to be?")
stringRange = int(input())
print("".join(secrets.choice(generatePass) for _ in range(stringRange)))
elif userInput.lower() == "c":
generatePass = string.ascii_letters + string.digits
print("How long do you want your string to be?")
stringRange = int(input())
print("".join(secrets.choice(generatePass) for _ in range(stringRange)))
else:
print("Not an option! Let's try again.")
userWelcome()
userWelcome()
However, my problem is what to do if the user inputs an incorrect option. As you can see, with the else statement I assume what they filled in does not match any of the earlier options - and so I want to try to rerun the generator again (so I try to call userWelcome again in the else statement).
However, when I type in for example 12 as input, my shell starts to output my string (Not an option Let's try again) literally a thousand times like it is stuck in a loop. I am wondering what I am doing wrong exactly.
What I have tried:
(1) So I have tried to solve this input problem first with try and except, running the except when there is a ValueError but that only works for numbers and I did not manage to rerun userWelcome()
(2) I have tried to create a elif statement in which I check the input for integers, however that also gets stuck in a loop. Code:
elif userInput.isalpha() == False:
print("Not an option! Let's try again.")
userWelcome()
Anyway, I hope that explains it well. I have been busy with this for a few hours now and I thought I'd ask this. Maybe it's a very stupid question but for me it's hard :)
TL;DR: Want to check for proper user input by running my function again, get stuck in weird loop
Thank you for your time and effort!
The code calls userWelcome() recursively, without changing the global variable userInput. The same bad string is processed again, causing the same result, which again calls userWelcome() - for ever (at least until max call depth).
You should read a new string at the beginning of userWelcome, instead of using a global variable. Also, recursion here is an overkill that confuses you. Better use a simple while loop:
while True:
userInput = ....
if ....
do something
return
elif ...
do something else
return # exit the function - breaking out of the loop
else:
print(error message)
# No return here, means the loop will continue to loop
If you want to call the function instead of loop inside, you can instead make the function return success (True) vs. failure (False), and loop that in the caller:
while not userWelcome(inputString):
inputString = read the string
def userWelcome(inputString):
if inputString == ....:
something
return True # To mark OK
elif inputString == .....:
something else
return True # To mark OK
else:
print an error
return False # To mark failure
Just avoid global variables, it is a bad practice. Pass the value through parameters, as in the code above.

Why isn't my program noticing the equivalency between letters?

I am working on making a simple game of Hangman in Python 2. The code I have so far is the ground work I have for it, but it doesn't seem to be working. If I could have a simple wake-up call as to what about what code I made isn't working I would appreciate it.
Code:
secret_word = 'tracy'
secret_word_list = []
for letter in secret_word:
secret_word_list += letter
print secret_word_list
def get_guess(guess = input("Guess: ")):
while len(guess) != 1:
print "Your guess must be exactly one character!"
guess = input("Guess: ")
while guess.isalpha() == False:
print "Your guess must be a lowercase letter!"
guess = input("Guess: ")
while guess.islower == False:
print "Your guess must be a lowercase letter!"
guess = input("Guess: ")
else:
return guess
while True:
if str(get_guess) in secret_word_list:
print "That letter is in the secret word!"
else:
print "That letter is not in the secret word!"
get_guess(guess = input("Guess: "))
Output:
Output of the Code
You've got several problems here, but the big one is that you're not calling functions, so you compare the function itself to the secret.
Code with fixes:
secret_word = 'tracy' # Don't make secret_word_list, there's no point; just use the str itself since you only test len 1 strings against it anyway
print secret_word
def get_guess(guess): # Don't make the default call input, that'll prompt once for an input and store it as the permanent default
while True:
# Test each condition and break loop only if all past; original code would never
# recheck length if new value entered after testing isalpha
if len(guess) != 1:
print "Your guess must be exactly one character!"
elif not guess.islower(): # Add missing call parens on islower; use not, never compare to False; islower implicitly verifies isalpha, so avoid testing isalpha
print "Your guess must be a lowercase letter!"
else:
break # Passed all tests, break loop
# Get new guess if any test failed
guess = raw_input("Guess: ") # Use raw_input on Python 2, never input (which eval's the result of raw_input)
# Removed else (loop always ends by breaking, using else nonsensical but harmless in original code too
return guess
while True:
# Move guess getting to if, because having it in else case never actually checked it
if get_guess(raw_input("Guess: ")) in secret_word:
print "That letter is in the secret word!"
else:
print "That letter is not in the secret word!"
Try it online!
Note: I kept the kinda odd behavior of having get_guess take an argument, but then reprompt for guesses on failure. A saner solution would be to remove the guess argument entirely, and move the guess = raw_input("Guess: ") to the top of the while loop (removing the else block at the end).
get_guess is a function, you need to put () after it to call the function.
You shouldn't put the call to input() as a default argument. The default value is evaluated once, when the function is defined, not every time the function is called. You should assign guess inside the function.
You should test for all the invalid inputs in a single loop.
def get_guess():
while True:
guess = input("Guess:")
if len(guess) != 1:
print "Your guess must be exactly one character!"
continue
if not guess.isalpha() or not guess.islower():
print "Your guess must be a lowercase letter!"
continue
break
return guess
while True:
guess = get_guess()
if guess in secret_word_list:
print "That letter is in the secret word!"
else:
print "That letter is not in the secret word!"

Calling function inside of function throws error

I am writing a "you think of a number and the computer has to guess it" type program. My code is here: http://pastebin.com/6Ny01PJV, and whenever it calls a function from another function it either ends the program or errors out.
def guess():
global guess
guess = choice(list)
if guess in cache:
guess()
else:
pass
print (guess)
cache.append(guess)
def check(guess):
global check
check = input("Was " + str(guess) + " the number? (y, n) ").lower()
if check == "n":
global wrong
wrong = input("Lower or higher? ").lower
elif check == "y":
playAgain = input ("I guessed the number! Play again? (y, n)")
if playAgain == "y":
#Right here it will error out with a TypeError
main()
if playAgain == "n":
exit()
else:
print("Please answer in the format 'y' or 'n'"
def reguess():
if wrong == "lower":
reguess = choice(list < guess)
#Here it will end the program, no crash, just no error given
check(reguess)
elif wrong == "higher":
#The same happens here
check(reguess)
reguess = choice(list > guess)
Whenever I type either 'higher' or 'lower', it ends the program.
Am I doing it wrong or is there an error in my code that I am not seeing?
You keep doing the same error over and over. I'll try to explain.
global list # already is globally defined on next line
list = list(range(0,11)) # list() is a function, you overwrite it here
print (list)
global cache # not necessary, again already global
cache = []
print ("Write down a number anywhere from 1-10.\nThe computer will try to guess your number.")
def guess(): # this defines a global function 'guess'
global guess # probably gets resolved to the function
guess = choice(list) # you overwrite the 'guess' function
Now, as I said, you keep having the same problem. You're making your variables overwrite the functions. You're then calling those variables as functions, as if you didn't overwrite anything.
So, TypeError: 'int' object is not callable. or something isn't callable.
Suggestion: remove global in favor of return the value from each function
Another problem I see
reguess = choice(list < guess)
Not clear what you expect that to do... list < guess is a boolean and you can't random.choice that.
TypeError: 'int' object is not callable means that you've done the equivalent of this:
def a(x):
return x+1
a = 1
a(2)
Here, we've defined a function with the name 'a', then redefined 'a' to be an int, then tried to call our function. This doesn't work because the name 'a' no longer refers to the function, but now refers to the integer 1.
Look at your code and I'm betting you'll see something similar to the above.

Python hangman module returns unexpected results

I'm a newbie writing hangman and have hit a bug in one of my modules. My intent in this module is to check the user input and verify it is a single character that is a letter and not a number. The error checking works in that it won't exit the module until a single letter ( or special, haven't figured a way around that yet) is entered but the return value is always the first user input entered not the last and correct entry. Any suggestions would be appreciated.
def get_guess():
guess = str(raw_input('Please enter your guess letter: '))
if len(guess) == 1:
try:
float(guess)
is_int = True
except ValueError:
is_int = False
if is_int:
print "You have entered a number not a letter."
get_guess()
else:
print "Please enter a single letter."
get_guess()
return guess
You are using recursion to get repeated inputs, but are not returning the recursive call results. You do need to return whatever the recursive call produced to pass it back up the stack:
return get_guess()
You'll need to do this in both locations you are calling get_guess() recursively.
Using recursion to get a response is not a good idea however; never underestimate the determination of idiots to get it wrong and instead hit your recursion limit. Use a loop instead:
def get_guess():
while True:
guess = raw_input('Please enter your guess letter: ')
if len(guess) == 1:
if guess.isdigit():
print "You have entered a number not a letter."
else:
return guess
else:
print "Please enter a single letter."
Here the function keeps looping endlessly until you return the one valid character guess. Note that you probably want to test for str.isalpha() instead if only letters are permitted. Your code and my version allow for anything that is not a digit, so spaces and punctuation are allowed too.
You may also want to study Asking the user for input until they give a valid response

Categories

Resources