using a function to call a class in a while loop - python

I'm currently writing a python gui that will ultimately generate a random village for use in tabletop RPG (mainly dungeons and dragons)
I have the code below that will generate a number of taverns based on how big a town the user wants and so far it works fine. I hope the GUI will eventually create shops, temples and other buildings too.
class NPC:
def __init__(self, first, last):
self.first = first
self.last = last
self.name = first + ' ' + last
class Tavern:
def __init__(self, name1, name2):
self.name1 = name1
self.name2 = name2
self.name = 'The ' + name1 + ' ' + name2
while num_tav != 0:
morf = random.randint(1, 2)
if morf == 1:
sex = 'male'
else:
sex = 'female'
first = open(set_race + '_' + sex + '.txt')
name1 = first.readlines()
first = random.choice(name1).strip()
last = open(set_race + '_surnames.txt')
name2 = last.readlines()
last = random.choice(name2).strip()
npcname = NPC(first, last)
tavern1 = open('tavnames1.txt')
name1 = tavern1.readlines()
name1 = random.choice(name1).strip()
tavern2 = open('tavnames2.txt')
name2 = tavern2.readlines()
name2 = random.choice(name2).strip()
tavern = Tavern(name1, name2)
print('Taverns/Inns: ' + tavern.name + "The inkeeper is a tall " + set_race + ' ' + sex + " named " + npcname.name + '\n')
num_tav = num_tav - 1
w.insert(END, not_b + 'Taverns/Inns: ' + tavern.name + "The inkeeper is a tall " + set_race + ' ' + sex + " named " + npcname.name + '\n' + 'Population is approx. ' + str(population) + ' people\n')
The NPC class basically genreates a random name and I'd like to use this in other areas (shops, markets, blacksmith, etc.), not just to generate the name of an innkeeper.
My question is;
Is it possible to create a function that will use the script
first = open(set_race + '_' + sex + '.txt')
name1 = first.readlines()
first = random.choice(name1).strip()
last = open(set_race + '_surnames.txt')
name2 = last.readlines()
last = random.choice(name2).strip()
npcname = NPC(first, last)
as a function that will call the NPC class, and then just have other while loops calls it? Instead of having the same code repeated in each of the loops I'll use to generate other buildings?
I'm assuming so but I just don't know what it would be called so any help is appreciated.

define the while loop in a function with maybe an extra parameter that gets the type of entity that it is supposed to generate (Tavern, shop,...) and then put it in another python file and import it. as a module.
def mynewfunction(set_race,sex):
first = open(set_race + '_' + sex + '.txt')
name1 = first.readlines()
first = random.choice(name1).strip()
last = open(set_race + '_surnames.txt')
name2 = last.readlines()
last = random.choice(name2).strip()
return NPC(first, last)
Then:
while (x,y,z):
npcname = mynewfunction(set_race):

Related

TypeError: can only concatenate str (not "dict") to str

All my variables seem to be string data types however I keep getting the above error message
elif menu == 'a':
pass
user_1 = input("Please enter a user name: ")
task_title = input("Please enter a title for the task to be done: ")
task_desc = input("Please describe the task: ")
task_due = input("Please enter due date of the task: ")
date_assign = str(date.today())
with open("task.txt", "a") as fa:
fa.write("\n" + {} + {} + {} + {} + {} + "No".format(task_title,task_desc,task_due,str(date_assign)))
Your brackets need to actually be within the string itself in order to use the str.format() function. So your code line:
fa.write("\n" + {} + {} + {} + {} + {} + "No".format(task_title,task_desc,task_due,str(date_assign)))
should look more like this:
fa.write("\n{} {} {} {} No".format(task_title,task_desc,task_due,str(date_assign)))
To add on to Nathan Robert's answer, consider using f-strings like so:
with open("task.txt", "a") as fa:
fa.write(f"\n{task_title} {task_desc} {task_due} {date_assign} No")
I find them to be much cleaner then '+' string concatenation.
You cannot create a format string with:
"\n" + {} + {} + {} + {} + {} + "No"
You could:
"\n" + repr({}) + repr({}) + repr({}) + repr({}) + repr({}) + "No"
Which will yield:
"\n{}{}{}{}{}No"
But if you want:
"\n + {} + {} + {} + {} + {} + No"
Then you just need to eliminate two "s.
"\n + {} + {} + {} + {} + {} + No"
Also note that you've provided 5 sets of brackets, but only four arguments to format. This suggests a possible error on your part.

How can I append new data into my .csv file without deleting the previous data

I made a maths quiz where the program asks and stores the user's name, the question, the solution and the user's score into a .csv file. My problem is that whenever the program is run the newly inputted data overwrites the previous data set, which I don't want so instead I want the new data to be appended below the old data set. How can I do this?
Here is my code so far:
import csv
import random
Name = input("Enter your name: ")
score = 0
a = random.randint(1,100)
b = random.randint(1,100)
Q1 = int(input(str(a) + " + " + str(b) + " = "))
A1 = a + b
x = random.randint(1,100)
y = random.randint(1,100)
Q2 = int(input(str(x) + " - " + str(y) + " = "))
A2 = x - y
if Q1 == A1:
score1 = score + 1
else:
score1 = score
if Q2 == A2:
score2 = score + 1
else:
score2 = score
with open("Quiz.csv", "w", newline="") as file:
writer = csv.writer(file)
writer.writerow([Name, "Question", "Solution", "Mark"])
writer.writerow([1, str(a) + " + " + str(b) , A1, score1])
writer.writerow([2, str(x) + " - " + str(y) , A2, score2])
You need to open the file in append mode, like this:
with open("Quiz.csv", "a", newline="") as file:

Pass variables to another module which contains classes

I have a module with a Class
class Record(object):
Name = ''
Gender = ''
Age = ''
Line = 'Bob=Male=40'
M = Line.split('=')
exec(M[0] + ' = ' + 'Record()')
exec(M[0] + '.' + 'Name' + ' = ' + "'" + M[0] + "'")
exec(M[0] + '.' + 'Gender' + ' = ' + "'" + M[1] + "'")
exec(M[0] + '.' + 'Age' + ' = ' + "'" + M[2] + "'")
I am trying to import the above module but to pass it the "Line" variable.
How could I do that ?
Adding this one line should do the job
# in main script
from lib import file_name
file_name.Line = Line #Assuming line is declared already
you need not declare Line in your module
You create objects by calling a class. You don't need to use exec to do that
#record.py
class Record:
def __init__(self, name, gender, age):
self.Name = name
self.Gender = gender
self.Age = age
def __str__(self):
return ' '.join((self.Name, self.Gender, self.Age))
Person = Record("Bob", "Male", "30")
# workspace.py
import record
print(record.Person)
Person2 = record.Record("Alice", "F", "30")
print(Person2)
Outputs:
Bob M 30
Alice F 30
In python you probably would get away with this
name = "Bob"
gend = "M"
age = '30'
exec(f'{name} = record.Record("{name}", "{gend}", "{age}")')
print(Bob)
# Bob M 30
But I would not advise that

How can I write this to a file

class PersonalInfo:
def set_titles(self, title):
self.__titles = title
def set_names(self, name):
self.__names = name
def set_addresses(self, add):
self.__addresses = add
def set_ages(self, age):
self.__ages = age
def set_numbers(self, number):
self.__numbers = number
# Accessor methods
def get_titles(self):
return self.__titles
def get_names(self):
return self.__names
def get_addresses(self):
return self.__addresses
def get_ages(self):
return self.__ages
def get_numbers(self):
return self.__numbers
def main():
# references PersonalInfo object
info = PersonalInfo()
# stores values in the object
info.set_titles(input("Enter Mr, Mrs, Miss:"))
info.set_names(input("Enter full name:"))
info.set_addresses(input("Enter address:"))
info.set_ages(input("Enter age:"))
info.set_numbers(input("Enter number:"))
#displays values stored in object's fields
print("Name: " + info.get_titles() + " " + info.get_names() + "\n"
+"Address: " + info.get_addresses() + "\n"
+ "Birth: " + info.get_ages() + "\n"
+ "Number: " + info.get_numbers() + "\n")
main()
main()
I want this to be printed out 2 times since I have 2 users who will answer the questions, but I can't seem to understand how to save the input answers in a text file. Can someone please give me an example??:)
I'm such a noob at this
Change your main() to init(self): And call it twice if you need run it twice. You could write a method to output the data to a file instead of including it in init if you wanted to.
def __init__(self):
# stores values in the object
self.title = self.set_titles(input("Enter Mr, Mrs, Miss: "))
self.name = self.set_names(input("Enter full name: "))
self.age = self.set_ages(input("Enter age: "))
self.address = self.set_addresses(input("Enter address: "))
self.number = self.set_numbers(input("Enter number: "))
# displays values stored in object's fields
print("Name: " + self.get_titles() + " " + self.get_names() + "\n"
+"Address: " + self.get_addresses() + "\n"
+ "Birth: " + self.get_ages() + "\n"
+ "Number: " + self.get_numbers() + "\n")
# Appends data to file
outfile = open('data_from_user.txt','a')
outfile.write("Name: " + self.get_titles() + " " + self.get_names() + "\n")
outfile.write("Address: " + self.get_addresses() + "\n")
outfile.write("Birth: " + self.get_ages() + "\n")
outfile.write("Number: " + self.get_numbers() + "\n")
outfile.close()
person_1 = PersonalInfo()
person_2 = PersonalInfo()
# storing data inside string
string = 'NAME: {} \n Address: {} \n Birth: {} \n Number: {} \n'.format(info.get_titles(),info.get_names(),
info.get_addresses(),info.get_ages(),info.get_numbers())
# printing 2 times
print(string,string,sep='\n')
# writing in a file
x = open('filename','a')
x.write(string)
x.close()

NameError: name 'countrychoice' is not defined

I'm having some trouble with the current program I'm writing.
I'm letting the user type in a country, and then a city city in that country, and then see a weather forecast for the choosen city using API.
I'm using a class, like this:
class requestChoice:
def __init__(self):
self.countrychoice = None
self.citychoice = None
def countryChoice(self):
self.countrychoice = input("Enter which country your city is in(in english): ")
def cityChoice(self):
self.citychoice = input("Enter the name of the city: ")
And my main program looks like this:
from requestchoice import requestChoice
import requests
if __name__ == '__main__':
"""Introducion"""
print ("\nThis program lets you see a weather forecast for your choosen city.")
rc = requestChoice()
while True:
print("\nWhen you have typed in country and city, press 3 in the menu to see the weather forecast for your choice.\n")
menu = input("\nPress 1 for contry\nPress 2 for city\nPress 3 to see forecast\nPress 4 to exit\n")
if menu == "1":
rc.countryChoice()
elif menu == "2":
rc.cityChoice()
elif menu == "3":
r = requests.get("http://api.wunderground.com/api/0def10027afaebb7/forecast/q/" + countrychoice + "/" + citychoice + ".json")
data = r.json()
try:
for day in data['forecast']['simpleforecast']['forecastday']:
print (day['date']['weekday'] + ":")
print ("Conditions: ", day['conditions'])
print ("High: ", day['high']['celsius'] + "C", '\n' "Low: ", day['low']['celsius'] + "C", '\n')
except Exception as e:
print ("\nHave you typed in the correct country and city?\nBecause we got a" ,e, "error")
else:
print ("\nGoodbye")
break
When I run my program I get the error NameError: name 'countrychoice' is not defined. It is going to be the same error with the citychoice. I've tried creating a list in my class and append the countrychoice to the list but without any luck. How am I supposed to make it work as wished?
You are getting a NameError on here:
r = requests.get("http://api.wunderground.com/api/0def10027afaebb7/forecast/q/" + countrychoice + "/" + citychoice + ".json")
because you have no names countrychoice and citychoice defined. Perhaps you meant to use rc.countrychoice and rc.citychoice instead?
You have to access them with the corresponding object name. In this case
rc.countrychoice
rc.citychoice
So, this line
r = requests.get("http://api.wunderground.com/api/0def10027afaebb7/forecast/q/" + countrychoice + "/" + citychoice + ".json")
becomes
r = requests.get("http://api.wunderground.com/api/0def10027afaebb7/forecast/q/" + rc.countrychoice + "/" + rc.citychoice + ".json")
You need to use rc.countrychoice and rc.citychoice here
r = requests.get("http://api.wunderground.com/api/0def10027afaebb7/forecast/q/" + rc.countrychoice + "/" + rc.citychoice + ".json")

Categories