How do I correctly define and call these functions?
I am trying to build an application that will prompt the main menu, go through a logon process, go to the next function, which would be the login menu and reference the inputs from the logon function so users do not have to input their card number and pin twice.
The issue I'm having is trying to be able to reference a variable in my second function, which is located in the same class. I'm being told by coworkers that using globals is bad and I shouldn't. Here is the code.
I've taken out some things as they aren't really important. I'd like to, for instance, use the elif choice ==3 statement to reference the original one_row.
p.s. I have changed def Login(self) to include the variables I'd like to reference, but then my main menu complains that the inputs have not been defined yet.
class LoginPrompt:
def Login(self):
while True:
print(menu[1])
self.Card_number=str(input('>> '))
print(menu[2])
self.Character_PINs = getpass.getpass('>> ')
self.one_row = c.execute('SELECT * FROM {tn} WHERE {cn}=? and {cnn}=?'.\
format(tn=table_1, cn=column_1, cnn=column_3), (self.Character_PINs, self.Card_number,))
for row in self.one_row.fetchone():
print('Welcome: ', row)
return
else:
print('PIN incorrect; try again')
def loginMenu(self):
while True:
print(menu[5])
print("\n1 - Deposit funds")
print("2 - Withdraw funds")
print("3 - Check balance")
print("4 - Reset Pin")
print("5 - Exit")
while True:
try:
choice = int(input("Please enter a number: "))
except ValueError:
print("This is not a number")
if choice >= 1 and choice <=5:
if choice == 1:
amount = input("\nPlease enter the deposit amount: ")
if amount != '' and amount.isdigit():
int(amount)
amount = c.execute('UPDATE {tn} SET Balances = ? WHERE {cn}=?'.\
format(tn=table_1, cn=column_2), (amount,))
else:
print("Please enter a valid number")
conn.commit()
conn.close
elif choice ==3:
print(Login.one_row)
elif choice ==5:
input('Enjoy your stay, and always remember to drink Nuka Cola! ')
return(mainMenu)
else:
return
def mainMenu():
print(menu[0])
chosen=False
while not chosen:
opt=int(input('\n Please choose one of the options below:\n\n-> Register for a new account [1]\n-> Login to an existing account [2]\n\nPlease type a number...\n\n>> '))
if opt==1:
userReg()
chosen=True
elif opt==2:
login_Menu = LoginPrompt()
login_Menu.Login()
chosen=True
login_Menu.loginMenu()
else:
print('\n\nPLEASE TYPE EITHER 1 OR 2...\n ')
print(chosen)
if __name__ == "__main__":
while True:
mainMenu()
Here, you instantiated a single instance of LoginPrompt and called Login and loginMenu on it:
login_Menu = LoginPrompt()
login_Menu.Login()
...
login_Menu.loginMenu()
Since you assign an instance variable self.one_row in Login, you can access the same instance variable via self.one_row in loginMenu:
class LoginPrompt:
def Login(self):
while True:
...
self.one_row = ...
...
def loginMenu(self):
while True:
...
while True:
...
if choice >= 1 and choice <=5:
...
elif choice == 3:
# print(Login.one_row)
print(self.one_row)
You can read more about self and instance variables in the Python documentation: https://docs.python.org/3.8/tutorial/classes.html#class-and-instance-variables
A note about code style
In Python, the convention is to:
name functions consistently in lower_case_with_underscores (and classes in CapWords), and
name instances after the class name.
login_prompt = LoginPrompt()
login_prompt.login()
...
login_prompt.login_menu()
You can read more about naming conventions in the PEP 8 style guide for Python code: https://www.python.org/dev/peps/pep-0008/#prescriptive-naming-conventions
Related
I'm working on a project/exercise where I need to use OOP in Python to create a Grade Book. I've been learning Python and working with 3.8.3 for about 6 weeks now, so I'm still fairly new. The grade book has a basic menu where you can add an assignment, quiz, and final exam grades. I must use a class with an empty list for both the quiz and assignment grades. I did a rough draft of the code after reading a bit on OOP, and managed to get the class to function without using attributes and only one method as below:
class GradeBook:
def main_function():
quiz_scores = []
assignment_scores = []
while True:
try:
quiz_grade = float(input('Please enter a grade for the quiz, or press Enter to stop adding grades: '))
quiz_scores.append(quiz_grade)
except:
break
while True:
try:
assignment_grade = float(input('Please enter a grade for the assignment, or press Enter to stop adding grades: '))
assignment_scores.append(assignment_grade)
except:
break
print (quiz_scores)
print (assignment_scores)
print ('time for totals and averages')
quiz_total = sum(quiz_scores)
assignment_total = sum(assignment_scores)
print ('quiz total ' + str(quiz_total))
print ('assign total ' + str(assignment_total))
if len(quiz_scores) > 0:
quizScoreAverage = sum(quiz_scores)// len(quiz_scores)
else:
quizScoreAverage = 0
if len(assignment_scores) > 0:
assignmentScoreAverage = sum(assignment_scores) // len(assignment_scores)
else:
assignmentScoreAverage = 0
print ('quiz average ' + str(quizScoreAverage))
print ('assign average ' + str(assignmentScoreAverage))
GradeBook.main_function()
Here is where I am running into my issues. I need to split the code up into several methods/functions, one for quiz scores, one for assignment scores, one that will store the final exam score and do nothing more, and one for getting the current grade/average. I've been searching and searching but have hit a wall. The code works up until I attempt to append the user's input to the list in the class. Again this is just a rough draft of the code as follows:
class GradeBook:
# Need this at attribute level for all instances to acccess as there will be an instance the pulls the list to calculate overall grade
assignment_scores = []
# quiz_scores = [] ### - This is the other list that will also be used for the grade
def assignGrade(self, score):
self.score = score
self.assignment_scores.append(score)
#####################################################
'''
This will be a duplicate of the above code but will use values to store quiz grades instead
def quizGrade(self, score):
self.score = score
self.quiz_scores.append(score)
'''
#####################################################
while True:
try:
assignment_grade = float(input('Please enter a grade for the assignment, or press Enter to stop adding grades: '))
# Program works just fine up until this point. My issue is here. Trying to feed the user input into the class instance
# to update the class list that is stored as an attribute. Instead of appending it seems to throw an error,
# because it doesn't continue the try loop for input and after the break when the list is printed, no values are shown
assignment_grade = GradeBook.assignGrade(assignment_grade) # <------- THIS IS THE PROBLEM CHILD OF MY CODING
except:
break
#####################################################
''' This block will be used to get input for the quiz grade to append to quiz scores list
while True:
try:
quiz_grade = float(input('Please enter a grade for the assignment, or press Enter to stop adding grades: '))
quiz_grade = GradeBook.quizGrade(quiz_grade) #not sure if this is right?
except:
break
'''
#####################################################
I guess I'm just not getting a good grasp on the whole idea of sending information from one instance to another. Any input is greatly appreciated. My plan is once it all gets figured out I just need to plug in the code to my final draft here:
class GradeBook:
# Initializes empty list to store quiz and assignment grades
quiz_scores = []
assignment_scores = []
#####################################################
def quizScore(self, score)
# lines of code to append user input to quiz list for reference in class
#####################################################
def assignScore(self, score)
# lines of code to append user input to assignment list for reference in class
#####################################################
def finalScore(self, score)
# line of code to store the final exam grade for reference in the class
#####################################################
def currentAverage(self)
if len(self.assignment_scores) > 0:
assignmentScoreAverage = sum(self.assignment_scores) // len(self.assignment_scores)
else:
assignmentScoreAverage = 0
if len(self.quiz_scores) > 0:
quizScoreAverage = sum(self.quiz_scores) // len(self.quiz_scores)
else:
quizScoreAverage = 0
currentGrade = (0.4 * self.final_grade) + (0.3 * quizScoreAverage) + (0.3 * assignmentScoreAverage)
return currentGrade
#####################################################
print('''
Grade Book
0: Exit
1: Enter assignment grade
2: Enter quiz grade
3: Enter final exam grade
4: Display current grade
''')
while True:
try:
selection = int(input('Please enter a choice: '))
if selection == 0:
quit
elif selection == 1:
while True:
try:
assignment_grade = float(input('Please enter a grade for the assignment, or press Enter to stop adding grades: '))
GradeBook.assignScore(assignment_grade)
except:
break
elif selection == 2:
while True:
try:
quiz_grade = float(input('Please enter a grade for the assignment, or press Enter to stop adding grades: '))
GradeBook.quizScore(quiz_grade)
except:
break
elif selection == 3:
while True:
try:
final_grade = float(input('Please enter a grade for the assignment, or press Enter to stop adding grades: '))
GradeBook.finalScore(final_grade)
except:
break
elif selection == 3:
final_grade = float(input('Please enter a grade for the final exam: '))
if isdigit(final_grade)
GradeBook.finalScore(final_grade)
else:
print('Please check your input and try again.')
elif selection == 4:
print(GradeBook.currentAverage())
else:
print('Please check your input and try again.')
continue
(Please, use snake case for all your code, including methods. Camel case should only be used for classes) In python I would recommend creating a module(file) without class for your main function. You are using the assignGrade method as a class method. Actually, you never even created an instance of your class! To create an instance, you should call the class as follows:
my_grades = GradeBook()
Now, my_grades is "a variable"(an instance) that contains all the properties(attributes) you defined for your class. You can access them as follows:
my_grades.assignment_scores
Your loop will fail because you have not passed the self argument to the function you pointed as the problem. In python, all instance methods start with the self argument, but it will be the variable(instance) before the dot. So, you should call it from an instance of your class and not from the class itself. Using the one I created from the first example, you can change the line to:
my_grades.assignGrade(assignment_grade)
That should do.
Instead of creating and calling a main_function, in the module add the following:
if __name__ == '__main__':
... # Create your instances and manipulate them here
So following the guidelines that were provided to us, as well as the example inputs, I have the program working as intended. Since this was just an introduction class, we didn't get into using methods in separate files, so I did not use:
if __name__ == '__main__':
However, I would like any comments on it like readability and other coding practices. Working code below:
# Programmed by thelastesquire92
# Programming Assignment 7 - Grade Book App
# SEC290.B2.32789
'''
Program that focuses on Object Oriented Programming.
The user is presented with simple text menu, and following
input prompts they are allowed to enter grades for quizzes,
assignments, and a final exam. The program then calculates
the average grade based off of these inputs.
'''
class GradeBook:
# Initializes empty list for quiz and assignment grades, sets default final score to 0
quiz_scores = []
assignment_scores = []
final_exam_score = 0
#####################################################
# Adds grade input to list of quiz scores
def quiz_score(self, score):
self.quiz_scores.append(score)
#####################################################
# Adds grade input to list of assignment scores
def assignment_score(self, score):
self.assignment_scores.append(score)
#####################################################
# Updates value of final exam score
def final_score(self, score):
GradeBook.final_exam_score = score
#####################################################
# Calculates current grade average
def current_average(self):
if len(GradeBook.assignment_scores) > 0:
assignment_score_average = sum(GradeBook.assignment_scores)\
// len(GradeBook.assignment_scores)
else:
assignment_score_average = 0
if len(GradeBook.quiz_scores) > 0:
quiz_score_average = sum(GradeBook.quiz_scores)\
// len(GradeBook.quiz_scores)
else:
quiz_score_average = 0
current_grade = (0.4 * GradeBook.final_exam_score)\
+ (0.3 * quiz_score_average)\
+ (0.3 * assignment_score_average)
return current_grade
#####################################################
# Prints out the menu for user
menu = ('''
Grade Book
0: Exit
1: Enter assignment grade
2: Enter quiz grade
3: Enter final exam grade
4: Display current grade
''')
print(menu)
#####################################################
# Main body of program that loops until user selects option to exit
while True:
# Creates instance of GradeBook
my_grades = GradeBook()
try:
selection = int(input('\nPlease enter a choice: '))
#####################################################
# Option 0 that exits the program
if selection == 0:
break
#####################################################
# Option 1 that allows input for assignment grades
elif selection == 1:
while True:
try:
assignment_grade = float(input('\nPlease enter a grade for the assignment: '))
my_grades.assignment_score(assignment_grade)
break
except:
print('\nPlease check your input and try again.')
continue
#####################################################
# Option 2 that allows input for quiz grades
elif selection == 2:
while True:
try:
quiz_grade = float(input('\nPlease enter a grade for the quiz: '))
my_grades.quiz_score(quiz_grade)
break
except:
print('\nPlease check your input and try again.')
continue
#####################################################
# Option 3 that allows input for final exam grade
elif selection == 3:
while True:
try:
final_grade = float(input('\nPlease enter a grade for the final exam: '))
my_grades.final_score(final_grade)
break
except:
print('\nPlease check your input and try again.')
continue
#####################################################
# Option 4 that displays current grade average
elif selection == 4:
average = my_grades.current_average()
print('\nYour current grade average is: ' + str(average))
else:
print('\nPlease check your input and try again.')
continue
except:
print('\nPlease check your input and try again.')
print(menu)
continue
Hopefully my code and question(s) are clear for understanding. If they are not please provide feed back.
I am fairly new to programing/coding so I decided to develop a program using Python that acts like a pizza ordering system. I eventually would like to use this code to develop a website using Django or Flask.
I have just finished the first step of this program where I am asking the user if this will be for delivery of pickup. Depending on what the user chooses the program will ask for specific information.
The area I feel like I am struggling with the most is developing classes and functions. specifically taking a variables from one function and using that variable in another function. I posted a past example of my code and I was advised that Global variables are not good to use in code. So I am trying really hard to refrain from using them.
Here is the code for reference:
import re
running = True
class PizzaOrderingSys():
"""order a customized pizza for take out or delivery """
def delivery_or_pickup(self): # Is the order for devilery or pickup?
print("\nWill this order be for pickup or delivery?")
self.delivery = input("P - pick up / D - delivery : ")
self.delivery = self.delivery.title()
if self.delivery == "D":
while running == True:
customerName = input("\nName for the order: ")
if not re.match("^[a-zA-Z ]*$", customerName):
print("Please use letters only")
elif len(customerName) == 0:
print("Please enter a vaild input")
else:
customerName = customerName.title()
break
while running == True:
customerPhoneNumber = input("\nEnter a phone number we can contact you at: ")
if not re.match("^[0-9 ]*$", customerPhoneNumber):
print("Please use numbers only")
elif len(customerPhoneNumber) == 0:
print("Please enter a a contact phone number")
else:
break
while running == True:
house_num = input("\nWhat is your house or unit number: ")
if not re.match("^[0-9 /]*$", house_num):
print("Please use numbers only")
elif len(house_num) == 0:
print("Please enter a valid input ")
else:
break
while running == True:
streetName = input("\nStreet name: ")
if not re.match("^[a-zA-Z ]*$", streetName):
print('Please use letters only.')
elif len(streetName) == 0:
print("Please enter a valid input")
else:
streetName = streetName.title()
break
while running == True:
city = input("\nCity: ")
if not re.match("^[a-zA-Z ]*$", city):
print("Please use letters only")
elif len(city) == 0:
print("Please enter a valid input")
else:
city = city.title()
break
while running == True:
zip_code = input("\nZip Code:")
if not re.match("^[0-9 /]*$", zip_code):
print("Please use numbers only")
elif len(zip_code) == 0 or len(zip_code) > 5:
print("Please enter a valid input")
else:
break
elif self.delivery == "P":
while running == True:
customerName = input("\nName for the order: ")
if not re.match("^[a-zA-Z ]*$", customerName):
print("Please use letters only")
elif len(customerName) == 0:
print("Please enter a valid input")
else:
customerName = customerName.title()
break
while running == True:
customerPhoneNumber = input("\nEnter a phone number we can contact you at: ")
if not re.match("^[0-9 ]*$", customerPhoneNumber):
print("Please use numbers only")
elif len(customerPhoneNumber) == 0:
print("Please enter a valid input")
else:
break
else:
print("Please enter P or D ")
delivery_or_pickup()
order = PizzaOrderingSys()
order.delivery_or_pickup()
My question is this: How would I use variables found in one function of my class and use it in another future function??
For example if I wanted to retrieve variables the functions customerName, customerPhoneNumber, house_num, streetName, city, Zip_code found in delivery_or_pick() function and use them in a function called:
def customer_receipt():
What would I need to do to my exiting code or to the def customer_receipt() function to obtain that information?
Any help with my questions or advise on any other area that stick out to you would be be greatly appropriated.
This is my second post on Stackoverflow so I apologize if what i am asking is unclear or the format of my question might is off, I am still learning.
Thank you again.
The idea here is that you can use your class variables to save data between method calls. Methods are functions that belong to a class. For example you could use Python's class initialization and create a dict of orders. Here is a simple example of such system, take a note of the usage of self keyword. self refers to the instance of the class and you can use it to access the variables or methods of the instance:
class PizzaOrderingSys:
def __init__(self):
# Initializing some class variables
self.running = True # Now you can use self.running instead of global running variable
self.orders = {}
def delivery_or_pickup(self):
# Somewhere at the end where you have collected the needed info
order = {
"zip_code": zip_code,
"city": city,
# You can enter all of the needed data similarly
}
order_id = "SomeIdHere" # ID could be anything, it just should be unique
self.orders[order_id] = order
return order_id
def customer_receipt(self, id):
# Now you can access all of the order here with self.orders
order = self.orders.get(id) # Select some specific order with id.
# Using get to avoid the situation
# where no orders or invalid id would raise an exception
if order:
receipt = f"Order {id}:\nCustomer city {order['city']}"
else:
receipt = None
return receipt
pizzasystem = PizzaOrderingSys()
order_id = pizzasystem.delivery_or_pickup()
receipt = pizzasystem.customer_receipt(order_id)
print(receipt)
# >>> Order 1235613:
# Customer city Atlantis
I recommend that you read more about classes, for example, python docs have great material about them.
Creating a small, simple ATM-like software. I've made functions for the various actions available. However in the output my global variable 'balance' isn't being updated. Below is the relevant snippet of code.
After some testing I realized that the value is understood to be changed within the function as when I deposit a value, I'm able to withdraw greater than the initial balance. So that means the variable is being updated for the functions at least.
global menu
balance = float(input("Please enter your current balance: "))
menu = "Current balance is: {}\n Press 1 to withdraw\n Press 2 to deposit\n Press 3 to exit".format(balance)
def display():
global choice
global balance
print(menu)
choice = input("Please select a number: ")
return balance
def deposit():
global balance
global choice
amount_dep = float(input("Please enter the amount you'd like to deposit: "))
balance += amount_dep
return "Your current balance is{}".format(balance)
def withdraw():
global balance
global choice
amount_with = float(input("Please enter the amount you'd like to withdraw: "))
if amount_with > balance:
print("Sorry, but your balance is less than the amount you'd like to withdraw.")
else:
balance -= amount_with
return "Your current balance is{}".format(balance)
while finished == False:
display()
global choice
if choice == '1':
withdraw()
elif choice == '2':
deposit()
elif choice == '3':
finished = True
print("Thank you for using our service.")
else:
print("You entered an invalid number, please retry")
So all the output is regular, except the value of balance.
When you define the variable menu at the top of the code, you define it with the initial balance. When you print the menu after a deposit or withdrawl, the display routine is still printing the menu defined with the initial balance.
You may be working on an assignment where you are supposed to use global variables, but this doesn't seem like a great use case. Your withdrawl function returns a string stating your current balance, but you don't use it. You could as easily call the withdrawl function with balance = withdraw(balance) and treat the balance as an argument and a return. Anyway, keep working it and keep learning!
I'm writing a very basic payment system on Python, but every time I enter the main() function and input a value it just quits the program. Any ideas?
import sys
def info():
usernames = ["15mermelstein_p","gril","jeff","example"]
passwords = ["test","pass","what","why"]
balances = [22.91,45.76,21.62,7.54]
a = input("What is your username? ").lower()
b = input("What is your password? ")
print(a)
print(b)
success = 0
for index in range(len(usernames)):
if usernames[index] == a and passwords[index] == b:
user_num = index
success = 1
break
if success == 1:
print("Login successful\n")
main()
return (a,b,user_num)
else:
print("Login unsuccessful")
info()
def main():
choice = input("-----Welcome to the new School Payment System-----\n1. Add money to account\n2. Change password\n3. Change your username\n4. Quit the program\n--------------------------------------------------\n")
if choice == "1":
credit = input("How much money would you like to deposit into your account? ")
temp_b = input("Please type in your password once againto confirm thios transaction: ")
if temp_b == info[2]:
balances[num(info[3])] += float(credit)
else:
print("The password you entered was incorrect, please return and try again. ")
elif choice == "2":
check_pass = input("Please input your current password first")
elif choice == "3":
sys.exit(0)
elif choice == "4":
sys.exit(0)
else:
sys.exit(0)
info()
Since you have provided no other information and the code runs fine on my machine, I am going to assume that your error is that you are running the wrong version of python. The code compiles with python-2.x but when you get to any of the inputs, it will not work as desired:
AJs-MacBook-Pro:~ $ python2 k.py
What is your username? "gril"
What is your password? "pass"
gril
pass
Login successful
-----Welcome to the new School Payment System-----
1. Add money to account
2. Change password
3. Change your username
4. Quit the program
--------------------------------------------------
1
AJs-MacBook-Pro:~ $
I ran your code with python3.x and it has some errors.
if temp_b == info[2]:
balances[num(info[3])] += float(credit)
You can subscript a function object. What you really need to do is either pass the correct username password to the main function so that it can be accessed in the main function to add balance and other things and validate the password again.
First of all, your program works fine apart from the below code,
if temp_b == info[2]:
balances[num(info[3])] += float(credit)
You are trying to access info as an array, but info is a function. (may be you have missed to define array for your payment system menu options).
I am completing a simple programming exercise (I am still new) where I am creating a character profile by allocating 30 points to 4 different character attributes. Program features are: show current profile, create a new profile, or change existing profile. First and second feature work fine, but there is problem with the last: the program is meant to unpack the nested list item (attribute + allocated score), ask for a new score, take the difference between the old and new and change the number of available points in the pool accordingly. Finally, add a new entry to the list (attribute + newly allocated score) at position 0 and then delete the entry at position 1, which should be the old entry for this attribute. Loop through the list, and done. However, once you execute the code you will see it won't work. Please see below the complete code:
options = ["Strength", "Health", "Wisdom", "Dexterity"]
profile = []
points = 30
choice = None
while choice != "0":
print(
"""
CHARACTER CREATOR PROGRAM
0 - Exit
1 - See current profile
2 - Build new profile
3 - Amend existing profile
"""
)
choice = input("Please choose an option: ")
print()
if choice == "0":
print("Good bye.")
elif choice == "1":
for item in profile:
print(item)
input("\nPress the enter key to continue.")
elif choice == "2":
print("You can now equip your character with attributes for your adventures.")
print("You have",points,"points to spent.")
print("Now configure your character: \n")
#Run the point allocation loop
for item in options:
point_aloc = int(input("Please enter points for " + str(item) + ":"))
if point_aloc <= points:
entry = item, point_aloc
profile.append(entry)
points = points - point_aloc
print("\nYour current choice looks like this: ")
print(profile)
input("\nPress the enter key to continue.")
else:
print("Sorry, you can only allocate", points," more points!")
print("\nYour current choice looks like this: ")
print(profile)
input("\nPress the enter key to continue.")
print("\nWell done, you have configured your character as follows: ")
for item in profile:
print(item)
input("Press the enter key to continue.")
elif choice == "3":
print("This is your current character profile:\n")
for item in profile:
print(item)
print("\nYou can change the point allocation for each attribute.")
for item in profile:
point_new = int(input("Please enter new points for " + str(item) + ":"))
attribute, points_aloc = item
diff = points_aloc - point_new
if diff >0:
points += diff
print("Your point allocation has changed by", -diff,"points.")
print(diff,"points have just been added to the pool.")
print("The pool now contains", points,"points.")
entry = item, point_new
profile.insert(0, entry)
del profile[1]
input("Press the enter key to continue.\n")
elif diff <0 and points - diff >=0:
points += diff
print("Your point allocation has changed by", -diff,"points.")
print(-diff,"points have just been taken from the pool.")
print("The pool now contains", points,"points.")
entry = item, point_new
profile.insert(0, entry)
del profile[1]
input("Press the enter key to continue.\n")
elif diff <0 and points - diff <=0:
print("Sorry, but you don't have enough points in the pool!")
input("Press the enter key to continue.\n")
else:
print("Sorry, but this is not a valid choice!")
input("Press the enter key to continue.\n")
input("\n\nPress the enter key to exit.")
Note: You need to create the profile first to run the changes.
Thanks in advance for your help!!
As the comments to your question indicate, you haven't asked your question in the best way. However, I see what's wrong with it. I could show you how to fix your current code, but the truth is that the best way to fix it is to rewrite it completely. As you do so, you should adopt the following strategies:
Break your code up into parts. In this case, I would advise you to create several different functions. One could be called main_loop, and would contain the logic for looping through the menu. It wouldn't contain any of the code for updating or displaying profiles. Instead, it would call other functions, display_profile, build_profile, and amend_profile. Those functions would accept variables such as options, profile, and points, and would return values such as options and points. This will enormously simplify your code, and make it much easier to test and debug. Here's an example of what main_loop might look like:
def main_loop():
options = ["Strength", "Health", "Wisdom", "Dexterity"]
profile = []
points = 30
choice = None
while choice != "0":
print(menu_string) #define menu_string elsewhere
choice = input("Please choose an option: ")
print()
if choice == "0":
print("Good bye.")
elif choice == "1":
display_profile(profile)
elif choice == "2":
profile, points = build_profile(options, profile, points)
elif choice == "3":
profile, points = amend_profile(profile, points)
else:
print("Sorry, but this is not a valid choice!")
input("Press the enter key to continue.\n")
input("\n\nPress the enter key to exit.")
See how much nicer this is? Now all you have to do is define the other functions. Something like...
def build_profile(options, profile, points):
# insert logic here
return profile, points
Another advantage to this approach is that now you can test these functions individually, without having to run the whole program.
Use the correct idioms for list modification. Modifying a list while iterating over it takes special care, and in some cases (such as when you change the length of the list by removing or adding items you've already iterated over) it won't work at all. There are ways to do what you try to do to profile, but for a beginning programmer I would recommend something much simpler: just create a new list! Then return that list. So in your amend_profile function, do something like this:
def amend_profile(profile, points):
# other code ...
new_profile = []
for item in profile:
attribute, points_aloc = item
# other code ...
new_proflie.append(entry)
# other code ...
return new_profile, points
Note also that this is where one of your main bugs is; you create an entry containing (item, point_new) instead of (attribute, point_new), so your new tuple has an item tuple inside it, instead of a lone attribute string as expected.