My variable is not updating after changing another variable affecting it - python

So I'm working a quiz on Python as a project for an Intro to Programming course.
My quiz works as intended except in the case that the quiz variable is not being affected by the new values of the blank array. On the run_quiz function I want to make the quiz variable update itself by changing the blanks to the correct answer after the user has provided it.
Here's my code:
#Declaration of variables
blank = ["___1___", "___2___", "___3___", "___4___"]
answers = []
tries = 5
difficulty = ""
quiz = ""
#Level 1: Easy
quiz1 = "Python is intended to be a highly " + blank[0] + " language. It is designed to have an uncluttered " + blank[1] + " layout, often using English " + blank[2] + " where other languages use " + blank[3] + ".\n"
#Level 2: Medium
quiz2 = "Python interpreters are available for many " + blank[0] + " allowing Python code to run on a wide variety of systems. " + blank[1] + " the reference implementation of Python, is " + blank[2] + " software and has a community-based development model, as do nearly all of its variant implementations. " + blank[1] + " is managed by the non-profit " + blank[3] + ".\n"
#Level 3: Hard
quiz3 = "Python features a " + blank[0] + " system and automatic " + blank[1] + " and supports multiple " + blank[2] + " including object-oriented, imperative, functional programming, and " + blank[3] + " styles. It has a large and comprehensive standard library.\n"
#Answer and quiz assignment
def assign():
global difficulty
global quiz
x = 0
while x == 0:
user_input = raw_input("Select a difficulty, Press 1 for Easy, 2 for Medium or 3 for Hard.\n")
if user_input == "1":
answers.extend(["readable", "visual", "keywords", "punctuation"])
difficulty = "Easy"
quiz = quiz1
x = 1
elif user_input == "2":
answers.extend(["operating systems", "cpython", "open source", "python software foundation"])
difficulty = "Medium"
quiz = quiz2
x = 1
elif user_input == "3":
answers.extend(["dynamic type", "memory management", "programming paradigms", "procedural"])
difficulty = "Hard"
quiz = quiz3
x = 1
else:
print "Error: You must select 1, 2 or 3.\n"
x = 0
def run_quiz():
n = 0
global tries
global blank
print "Welcome to the Python Quiz! This quiz follows a fill in the blank structure. You will have 5 tries to replace the 4 blanks on the difficulty you select. Let's begin!\n"
assign()
print "You have slected " + difficulty + ".\n"
print "Read the paragraph carefully and prepare to provide your answers.\n"
while n < 4 and tries > 0:
print quiz
user_input = raw_input("What is your answer for " + blank[n] + "? Remember, you have " + str(tries) + " tries left.\n")
if user_input.lower() == answers[n]:
print "That is correct!\n"
blank[n] = answers[n]
n += 1
else:
print "That is the wrong answer. Try again!\n"
tries -= 1
if n == 4 or tries == 0:
if n == 4:
print "Congratulations! You are an expert on Python!"
else:
print "You have no more tries left! You can always come back and play again!"
run_quiz()
I know my code has many areas of improvement but this is my first Python project so I guess that's expected.

The problem is that your variable, quiz, is just a fixed string, and although it looks like it has something to do with blanks, it actually doesn't. What you want is 'string interpolation'. Python allows this with the .format method of str objects. This is really the crux of your question, and using string interpolation it's easy to do. I'd advise you to take some time to learn .format, it's an incredibly helpful function in almost any script.
I've also updated your code a bit not to use global variables, as this is generally bad practice and can lead to confusing, difficult to track bugs. It may also impair the uncluttered visual layout :). Here is your modified code, which should be working now:
quizzes = [
("""\
Python is intended to be a highly {} language.\
It is designed to have an uncluttered {} layout,\
often using English {} where other languages use {}
""", ["readable", "visual", "keywords", "punctuation"], "Easy"),
("""\
Python interpreters are available for many {}\
allowing Python code to run on a wide variety of systems.\
{} the reference implementation of Python, is {}\
software and has a community-based development model, as\
do nearly all of its variant implementations. {} is managed by the non-profit {}
""", ["operating systems", "cpython", "open source", "python software foundation"], "Medium"),
("""\
Python features a {} system and automatic {} and\
supports multiple {} including object-oriented,\
imperative, functional programming, and\
{} styles. It has a large and comprehensive standard library.
""", ["dynamic type", "memory management", "programming paradigms", "procedural"], "Hard")
]
#Answer and quiz assignment
def assign():
while True:
user_input = raw_input("Select a difficulty, Press 1 for Easy, 2 for Medium or 3 for Hard.\n")
if user_input == "1":
return quizzes[0]
elif user_input == "2":
return quizzes[1]
elif user_input == "3":
return quizzes[2]
else:
print "Error: You must select 1, 2 or 3.\n"
continue
break
def run_quiz():
n = 0
#Declaration of variables
blank = ["___1___", "___2___", "___3___", "___4___"]
tries = 5
print "Welcome to the Python Quiz! This quiz follows a fill in the blank structure. You will have 5 tries to replace the 4 blanks on the difficulty you select. Let's begin!\n"
quiz, answers, difficulty = assign()
print "You have selected {}.\n".format(difficulty)
print "Read the paragraph carefully and prepare to provide your answers.\n"
while n < 4 and tries > 0:
print quiz.format(*blank)
user_input = raw_input("What is your answer for {}? Remember, you have {} tries left.\n".format(blank[n], tries))
if user_input.lower() == answers[n]:
print "That is correct!\n"
blank[n] = answers[n]
n += 1
else:
print "That is the wrong answer. Try again!\n"
tries -= 1
if n == 4 or tries == 0:
if n == 4:
print "Congratulations! You are an expert on Python!"
else:
print "You have no more tries left! You can always come back and play again!"
run_quiz()
A little more on string interpolation:
You're doing a lot of "start of string " + str(var) + " end of string". This can be achieved quite simply with "start of string {} end of string".format(var)" - it even automatically does the str conversion. I've changed your quiz variables to have "{}" where either "__1__" etc should be displayed or the user's answer. You can then do quiz.format(*blank*) to print the 'most recent' version of the quiz. * here 'unpacks' the elements of blank into separate arguments for format.
If you find it more easy to learn with example usage, here are two usages of format in a simpler context:
>>> "the value of 2 + 3 is {}".format(2 + 3)
'the value of 2 + 3 is 5'
>>> a = 10
>>> "a is {}".format(a)
'a is 10'
I've also stored the information about each quiz in a list of tuples, and assign now has a return value, rather than causing side effects. Apart from that, your code is still pretty much intact. Your original logic hasn't changed at all.
Regarding your comment about objects:
Technically, yes, quizzes is an object. However, as Python is a 'pure object oriented language', everything in Python is an object. 2 is an object. "abc" is an object. [1, 2, 3] is an object. Even functions are objects. You may be thinking in terms of JavaScript - with all of the brackets and parentheses, it kind of resembles a JS Object. However, quizzes is nothing more than a list (of tuples). You might also be thinking of instances of custom classes, but it's not one of those either. Instances require you to define a class first, using class ....
A bit more on what quizzes actually is - it's a list of tuples of strings, lists of strings and strings. This is a kind of complicated type signature, but it's just a lot of nested container types really. It firstly means that each element of quizzes is a 'tuple'. A tuples is pretty similar to a list, except that it can't be changed in place. Really, you could almost always use a list instead of a tuple, but my rule of thumb is that a heterogenous collection (meaning stuff of different types) should generally be a tuple. Each tuple has the quiz text, the answers, and the difficulty. I've put it in an object like this as it means it can be accessed by indexing (using quiz[n]), rather than by a bunch of if statements which then refer to quiz1, quiz2, etc. Generally, if you find yourself naming more than about two variables which are semantically similar like this, it would be a good idea to put them in a list, so you can index, and iterate etc.

Only now have I read your question properly.
You first make your strings quiz1, quiz2 an quiz3.
You only do that once.
After that you change your blanks array.
But you don't reconstruct your strings.
So they still have the old values.
Note that a copy of elements of the blanks array is made into e.g. quiz1.
That copy doesn't change automagically after the fact.
If you want to program it like this, you'll have to rebuild your quiz1, quiz2 and quiz3 strings explicitly each time you change your blanks array.
General advice: Don't use so many globals. Use function parameters instead. But for a first attempt I guess it's OK.
[edit]
A simple modification would be:
Replace your quiz, quiz1, quiz2 and quiz3 by functions get_quiz (), get_quiz1 () etc. that get the most recent version, including the altered elements of blanks.
This modification doesn't make this an elegant program. But you'll come to that with a bit more experience.
A long shot in case you wonder (but don't try to bridge that gap in one step):
In the end Quiz will probably be a class with methods and attributes, of which you have instances.
To be sure: I think that experimenting like this will make you a good programmer, more than copying some ready to go code!

Related

Certain variables assigned by functions are not being assigned in python script

I am working on procedural generation of character concepts. As part of this, I have set variables to change the pronouns in text so they will be correct for the generated character. However, for some reason, my code refuses to assign variables for this, resulting in output like "Bob is a Caucasian . works as..." It should read "Bob is a Caucasian male. He works as..."
Everywhere a pronoun or the word male or female should be, it prints nothing. Not to console, nor to file. When I strip the entire script down to just the code that calls for the function to run, and the function itself, it still wont assign the variables.
Other systems that use functions to assign variables are working 100% fine.
I've rewritten new functions 3 times to try different approaches to this. I've tried making the variables global. I don't know what else to try.
Here is the function.
def pronouns(sex1):
pronoun1, pronoun1alternate, pronoun2, pronoun2alternate = "", "", "", ""
if sex1 == "male":
pronoun1 = "He"
pronoun1alternate = "he"
pronoun2 = "His"
pronoun2alternate = "his"
elif sex1 == "female":
pronoun1 = "She"
pronoun1alternate = "she"
pronoun2 = "Her"
pronoun2alternate = "her"
return pronoun1, pronoun1alternate, pronoun2, pronoun2alternate
The variable sex1 is created much later on, and cannot be created within this function as I may want to expand this program for fantasy and sci-fi character concepts later on and decided to handle sex selection with each individual race in case I want to do something like Species-8472 in the future.
Here is how the function called later on.
p1, p1a, p2, p2a = pronouns(sex1)
I have been informed that python passes the values but not names. It didn't work when the function outputted p1 p1a and so on either. I was told using different names in the same order might fix the problem. It did not.
Here his how the variables are supposed to be used.
description = name + " is a " + race + " " + sex + ". " + p1 + " has " + eyes + " eyes. " + colorapp
It has no problem filling out the name, race, eye color, and the colorapp variable, but cannot ever, regardless of what I do, fill out sex, or any pronoun values.
No error messages occur when this code is run in isolation. It will print blank lines if asked to just print the pronouns or sex. However, sex1 will print successfully, as will almost every other variable in the program.
How are you assigning value to variable sex1? Make sure it is passed in lowercase. If this is the problem you can use sex1.lower() on lines 3 and 8 of the function.

If and Else statement Variable Question in Python

I am still pretty new to Python and learning! I searched around and some postings seem too complex for me at this time. Wondering why the car_brandp below is not joining with "and quite expensive" after the else function initiates? The first else line prints fine but it seems like I can't put that message as a variable?
I got the None Type error
car_brand =input ("What is the best car brand? ")
if car_brand == ("Range Rover"):
print (car_brand + " is the best car brand ever!")
else:
car_brandp = print (car_brand + " is just personal taste..")
print (car_brandp + " and quite expensive...")
This line:
car_brandp = print (car_brand + " is just personal taste..")
is suppose to be:
car_brandp = (car_brand + " is just personal taste..")
"print" is a procedure to display something in the console. A procedure differs from a function as it is not meant to return something of value, but rather perform something as a side effect (it will do something useful but you cannot interact with it). You may not assign the return value of the print function as it is meaningless.
Since you are still new to Python, it is a good idea to learn the proper habits early. In particular, PEP8 contains valuable information on style and conventions that most Python developers follow. Such recommendations are optional, but when followed, they help other developers understand your code better.
car_brand = input("What is the best car brand? ")
if car_brand == "Range Rover":
msg = car_brand + " is the best car brand ever!"
else:
msg = car_brand + " is just personal taste.."
msg += " and quite expensive..."
print(msg)
print() is like a void function in other languages. So, it does something, but it returns nothing (None, in python, like null in other languages).
So, in your next line, you are trying to add
None + "personal taste"
and you get an error because addition of string and None is not defined
So, you options are
consecutive prints
concatenate strings eg print( str(brand) + "personal taste")
formatted strings eg print( f'{brand} personal taste')

Python beginner here : TypeError: 'str' object does not support item assignment

I just started programming with python a couple days ago with no prior experience in programming.
I've been following tutorials online and decided to challenge myself by making a hangman-esque game. I'm trying to make it so that a guess replaces the position an alphabet in the hidden word but python is returning this error. Right now the word is called name and the hidden_name are just #'s in the same length.
name = input ("what is your name ::")
hidden_name = ("#" * len(name))
print (hidden_name)
guess = input ("Guess a letter ::")
def guess_update(guess, name, hidden_name):
right = guess in name
i = 0
for c in name:
if c == guess:
hidden_name[i] = c
i += 1
if guess in name:
guess_update(guess, name, hidden_name)
print ("Your progess is ::", hidden_name)
Thanks for helping this newbie out :)
Strings in Python are immutable, so you cannot do this:
hidden_name[i] = c
One option which will achieve the desired effect for your game is:
hidden_name = hidden_name[:i] + c + hidden_name[i+1:]
This works because you are creating a new string using concatenation, and re-assigning the result back to the variable, rather than attempting to edit the existing string.
Strings in python are inmutable, so you cannot change its content.
One solution would be to split the string, change the letter and stick it back together:
splitted = list(hidden_name)
splitted[i] = c
hidden_name = ''.join(splitted)

Creating Decision Tree for Simple Game

I am currently a new student learning python. This is my first real experience doing much computer coding. For my project I must create a fill in the blank quiz with three different levels of difficulty. Once the user chooses a difficulty the game should print a different paragraph based on the difficulty. Each section of the game works fine but I am having trouble creating the "difficulty chooser." No matter the difficulty I choose, the game rolls through the easy, medium, and the hard level in order and then crashes.
Below I have included the introductory text and the difficulty chooser. I would love some help. I am sure there are really obvious things I don't see. Thank you!
def introduction():
print '''Welcome to Kevin's European Geography Quizzes.
Test your knowledge of European geography. \n'''
difficulty = raw_input('''Do you want to play an easy, medium, or hard game?
Please type the number 1 for easy, 2 for medium, or 3 for hard.\n''' )
game_chooser(difficulty)
def game_chooser(difficulty):
cursor = 0
difficulty_choice = [easy_game(), medium_game(), hard_game()]
#each element of the above list links to a procedure and starts one of the
#mini-games.
while cursor < len(difficulty_choice):
if difficulty != cursor:
cursor += 1
else:
difficulty_choice[cursor]
break
You can do with if else if you only want to print something but if you have separate code block for each level then define a function for each level and use this pattern :
You can define the function blocks and call them basis on user input something like:
# define the function blocks
def hard():
print ("Hard mode code goes here.\n")
def medium():
print ("medium mode code goes here\n")
def easy():
print ("easy mode code goes here\n")
def lazy():
print ("i don't want to play\n")
# Now map the function to user input
difficulty_choice = {0 : hard,
1 : medium,
4 : lazy,
9 : easy,
}
user_input=int(input("which mode do you want to choose : \n press 0 for hard \n press 1 for medium \n press 4 for lazy \n press 9 for easy "))
difficulty_choice[user_input]()
Then invocation of function block will be:
difficulty_choice[num]()
Add a conditional for the input.
if difficulty == 'easy':
print("here is an easy game")
elif difficulty == 'medium':
print('here is a medium game')
elif difficulty == 'hard':
print('here is hard')
else:
print('Please enter valid input (easy, medium, hard)')
Under each if statement put your game code.
The reason your code goes through all the difficulties is because of this line:
difficulty_choice = [easy_game(), medium_game(), hard_game()]
When Python sees something like easy_game(), it calls the easy_game function and replaces it with the result. You don't want to call the function yet though, so you can take off the parenthesis to store just the function instead:
difficulty_choice = [easy_game, medium_game, hard_game]
This will mean you have to call the function after you take it out of the array.
As for the crash, when you use raw_input() you get a string back. That means when you type in the 1 to decide for an easy game, you get the character 1, which is represented by the number 49. That's why your code goes through everything and crashes: Your 1 is really a 49. In fact, if you type 1 < '1' into the interpreter, you'll get True back.
To fix that, you can pass the result of raw_input() to the int() function, which will parse it and give you the proper integer (or throw an exception if it can't be parsed). The last line of introduction would then look like game_chooser(int(difficulty)).
You could also skip most of the code of game_chooser by just indexing into the array (that's what they're for, after all):
def game_chooser(difficulty):
# the lack of parens here means you get the function itself, not what it returns
difficulty_choice = [easy_game, medium_game, hard_game]
#each element of the above list links to a procedure and starts one of the
#mini-games.
# note the parens to actually call the retrieved function now
difficulty_choice[difficulty]()

Variables don't change after being run through a function

I'm writing a small game in python in which certain events happen and effect variables which need to stay in certain parameters. I have the main file and then another file which has all of the events in them. Some of the values are changed in the function then supposed to change the overall values in main (Sorry if that doesnt make sense)
Here's the part in main:
while (army > -100 and army < 100 and people > -100 and people < 100 and church > -100 and church < 100 and affairs > -100 and money < 100 and money > -100):
os.system('clear')
#Top Bar. Should Stay throughout game.
print("[-]==[King: " + king + "]==[Years in power:" + str(years) +"]==[Army: " + str(army) + "]==[People: " + str(people) + "]==[Church: " + str(church) + "]==[Foreign Affairs: " + str(affairs) + "]==[Economy: " + str(money) +"]==[-]")
print(people)
event1(army, people, church, affairs, money, years)
That loops until one of the parameters falls below 0 then there's losing conditions
Right now there is only one event, and it's not quite finished, but I only need one thing to at least see a change in the values.
Here that:
def event1(army, people, church, affairs, money, years):
#Feilds are Flooding
print("")
print("Sire! The Feilds in the eastern baronies are flooding! What should we do?")
print("")
print("Choices:")
print("1: The rain will pass, do nothing. (~Money, People)")
print("2: Have the Royal Builders build flood protection! (~Money, People)")
print("")
c=input("Your choice sire: ")
while True:
if c > 2:
print("")
print("Please chose a valid option")
print("Your choice sire: ")
continue
if c == 1:
time.sleep(2)
print("")
print("You do nothing, your people starve from flooded feilds (-People, +Money)")
money = money+20
people = people-20
years = years+1
raw_input("Press Enter to go to the next year")
return money
return years
return people
break
After it runs the event the values people, money and years are all supposed to change, but when it loops, nothing changes.
Any help is appreciated! Thank you!
Those are local variables. As soon as you leave the method scope, the value is lost, unless you return and actually use the returned values.
In your caller, assign your variables with the new returned values:
money, years, people = event1(army, people, church, affairs, money, years)
and in event1, perform only one return (others are unreachable) of the tuple containing the 3 values you want to return (which is unpacked to the 3 upper level eponymous variables):
return money, years, people
YOU DO NOT NEED THE RETURN!!!!!!!!!!!!!!!!!!!! COMPLETELY REMOVE IT! READ THIS! (should help)
The return in fact ruins your command, and there is a really easily explainable way to understand how it works.
First I need to explain something, because I am kind of confused about your code. Return is used to make the value of your command whatever you have returned. Return is used like this:
def AddThreethousandTwohundredSeventyNineToNum(num):
num = num + 3279
return num
and then
print AddThreethousandTwohundredSeventyNineToNum(4)
It should print "3283". (3279 + 4)
print printThreethousandTwohundredSeventyNineToNum(2)
It will print "3281".
You can also do cool things like:
if AddThreethousandTwohundredSeventyNineToNum(x) == y:
DoSomething
All return does is make the value OF THE FUNCTION whatever you want it to be. In the last code, the function looks for what I made num, and sees that it is 4 or 2, so it does num = num + 3279, so num gets increased by 3279 (3273 or 3271). When you do return num, it makes THE FUNCTION equal num.
That means what you have done is changed all those beatiful values in lines 21-23 (money, people, etc.) and technically that is all you had to do. However, when you returned the numbers, you made your command not only change those values, but also become a number, and obviously you cant just have a number lying around in your command. Or else the interpreter will not understand.
I hope I was clear enough, and if not, please please PLEASE tell me (please).

Categories