I am looking to create instances of a class from user input - python

I Have this class:
class Bowler:
def __init__(self, name, score):
self.name = name
self.score = score
def nameScore(self):
return '{} {}'.format(self.name, self.score)
I need to get user input until a blank line is entered. Then use the data I got to create instances of a class. I was thinking something like:
def getData():
name, score = input("Please enter your credentails (Name score): ").split()
B1 = Bowler(name, score)
print(B1.nameScore())
But then I would somehow have to loop it until I get a blank user input. Also I would somehow have to create B2 B3 B4 etc in the loop.
Sorry I am still really new to programming, maybe I am looking at this from the wrong angle.

What you're looking for are Python Lists. With these you will be able to keep track of your newly created items while running the loop. To create a list we simply defined it like so:
our_bowlers = []
Now we need to alter our getData function to return either None or a new Bowler:
def getData():
# Get the input
our_input = input("Please enter your credentails (Name score): ").split()
# Check if it is empty
if our_input == '':
return None
# Otherwise, we split our data and create the Bowler
name, score = our_input.split()
return Bowler(name, score)
and then we can run a loop, check for a new Bowler and if we didn't get anything, we can print all the Bowlers we created:
# Get the first line and try create a Bowler
bowler = getData()
# We loop until we don't have a valid Bowler
while bowler is not None:
# Add the Bowler to our list and then try get the next one
our_bowlers.append(bowler)
bowler = getData()
# Print out all the collected Bowlers
for b in our_bowlers:
print(b.nameScore())

This is my code to do what you want:
class Bowler:
def __init__(self, name, score):
self.name = name
self.score = score
def nameScore(self):
return '{} {}'.format(self.name, self.score)
def getData():
try:
line = input("Please enter your credentails (Name score): ")
except SyntaxError as e:
return None
name, score = line.split()
score = int(score)
B = Bowler(name, score)
print(B.nameScore())
return B
if __name__ == '__main__':
bowlers = list()
while True:
B = getData()
if B == None:
break
bowlers.append(B)
for B in bowlers:
print(B.nameScore())
In addition, I recommend you to modify your input for it's inconvenient now

Related

How do I make a class instance using user input?

I am making a text based adventure game in python. Once the game begins, I would like to create an instance of a class called "Character" which is the player's character object. I would like the user to be able to choose the race of the character they want to play. So far I have:
class Race:
def __init__(self, name, passive, hp):
self.name = name
self.passive = passive
self.hp = hp
and
class Lizard(Race):
def __init__(self, name, passive, hp):
super().__init__(name, passive, hp)
self.name = 'Lizardman'
self.passive = 'Regrowth'
self.hp = 20
def regrowth(self):
if 0 < self.hp <= 18:
self.hp += 2
and
def race_select():
races = ['Lizard']
while True:
for i, j in enumerate(races):
print(f"[{i + 1}]", j)
choice = int(input('Pick a race:'))
if choice <= len(races):
print('You are a ', races[choice - 1])
return races[choice - 1]
else:
continue
If I understand correctly, if I wanted the race to be a Lizard, I would still have to do
character = Lizard('Lizardman', 'Regrowth', 20)
Is there an easy way to let the user choose the race and the object to be created accordingly? Thanks
A simple solution would be to map a name to a class using a dictionary. As a simple example:
race_map = {"lizard": Lizard,
"human": Human} # I'm adding a theoretical other class as an example
choice = input('Pick a race:')
race_initializer = race_map.get(choice, None) # Get the chosen class, or None if input is bad
if race_initializer is None:
# They entered bad input that doesn't correspond to a race
else:
new_creature = race_initializer(their_name, their_passive, their_hp)
new_creature is now the new object of the chosen class.
You may want to standardize the input using choice.lower() to ensure that capitalization doesn't matter when they enter their choice.
I changed it to allow for specifying a race by a string name instead of a number. If you wanted a number, you could keep your list, but apply the same idea. Something like:
race_list = races = [('Lizard', Lizard), ('human', Human)]
choice = int(input('Pick a race:'))
try:
race_initializer = race_list[choice][1] # 1 because the class object is the second in the tuple
new_creature = race_initializer(their_name, their_passive, their_hp)
except IndexError:
# Bad input
I included the name in the race_list so that you can loop over the list and print out index->name associations for the user to pick from.
You may also want to use a more robust structure than a plain tuple to store name->initializer mappings, but it works well in simple cases.

"AttributeError: 'list' object has no attribute 'SMSMessage'"

I have tried many ways but can't seem to get the length of my list through the method in my class my code:
SMSStore = []
unreadMessage = []
class SMSMessage(object):
def __init__(self, hasBeenRead, messageText, fromNumber):
self.hasBeenRead = hasBeenRead
self.messageText = messageText
self.fromNumber = fromNumber
hasBeenRead = False
def markAsRead(self, hasBeenRead):
hasBeenRead = True
def add_sms(self):
newMessage = (self.hasBeenRead, self.messageText, self.fromNumber)
return SMSStore.append(newMessage)
def get_count():
return len(SMSStore)
def get_message(self, i):
hasBeenRead = True
return SMSStore[i][1]
def get_unread_messages(i):
for i in SMSStore:
if SMSStore[i][0] == False:
unreadMessage.append(SMSStore[i])
print unreadMessage
def remove(self, i):
return SMSStore.remove(i)
This is how a message in the list would ideally look like:
#sample = SMSMessage(False, "Hello friend!", 0742017560)
And here is how the class is used
userChoice = ""
while userChoice != "quit":
userChoice = raw_input("What would you like to do - read/send/quit?")
if userChoice == "read":
print len(SMSStore)#this way i can get the length of the list anyway without using get_count
SMSStore(get_count()
unreadChoice = raw_input("Would you like to retrieve all unread messages or one of your own choice? - all unread/custom ")
if unreadChoice == "custom":
i = int(raw_input("Please enter which message number you want to read: "))
print get_message(i) #I dont understand how i works and how to get it working with the object definition
elif userChoice == "send":
messageText = raw_input("Please type in your message: ")
fromNumber = raw_input("Please type in the number it was sent from ")
newObject = SMSMessage(False, messageText, fromNumber)
newObject.add_sms()
print SMSStore
elif userChoice == "quit":
print "Goodbye"
else:
print "Oops - incorrect input"
I can just use len(SMSStore) but I want to be able to use the method inside the class to get it. Can point out any mistakes?
This was the question asked:
Open the file called​  sms.py​
Create a class definition for an SMSMessage which has three variables:
hasBeenRead, messageText, and fromNumber. 
The constructor should initialise the sender’s number. 
The constructor should also initialise hasBeenRead  to false
Create a method in this class called MarkAsRead which should change hasBeenRead to true.
Create a list called SMSStore to be used as the inbox.
Then create the following methods:
add_sms - which takes in the text and number from the received sms to
make a new SMSMessage object. 
get_count - returns the number of messages in the store.
get_message - returns the text of a message in the list.Forthis, allow the
user to input an index i.e. GetMessage(i) returns the message
stored at position i in the list. Once this has been done,
hasBeenRead should now be true. 
get_unread_messages - should return a list of all the messages which
haven’t been read. 
remove - removes a message in the SMSStore. 
Now that you have these set up, let’s get everything working! 
in your SMSMessage class
def get_count(self, *args):
return len(SMSStore)
in your script
# create instance
sms_msg = SMSMessage() # init arg needed
print sms_msg.get_count()
SMSStore is a global variable, you could remove get_count from SMSMessage scope
SMSStore = []
unreadMessage = []
class SMSMessage(object):
...functions...
def get_count(*args):
return len(SMSStore)
and call it regularly OR
ls = range(20)
class A(object):
# declare default value for your arguments
def __init__(self, hasBeenRead = False, messageText = "", fromNumber=0):
self.a = a
self.b = b
#using classmethod
#classmethod
def get_count(cls, *args):
return len(ls)
print A.get_count()

Yatzy, how do I refer to my Player-attributes?

I have a huge problem right now, I cannot refer to my Player-attributes, my code is looking like this currently:
from terminaltables import AsciiTable
class Player:
def __init__(self,name):
self.name=name
self.ones=0
self.twos=0
self.threes=0
self.fours=0
self.fives=0
self.sixs=0
self.abovesum=0
self.bonus=0
self.onepair=0
self.twopair=0
self.threepair=0
self.fourpair=0
self.smalladder=0
self.bigladder=0
self.house=0
self.chance=0
self.yatzy=0
self.totalsum=0
#self.lista={"ones":0,"twos":0,"threes":0, "fours":0,"fives":0,"sixs":0,"abovesum":0,"bonus":0,"onepair":0,"twopair":0,"threepair":0,"fourpair":0,"smalladder":0,"bigladder":0,"house":0,"chance":0,"yatzy":0,"totalsum":0}
def __repr__(self):
return self.name
def __str__(self):
return self.name
def countbonus(self):
self.abovesum=self.ones+self.twos+self.threes+self.fours+self.fives+self.sixs
if self.abovesum>=63:
self.bonus+=50
return self.abovesum, self.bonus
else:
return self.abovesum, self.bonus
def counttotalsum(self):
self.totalsum=self.abovesum+self.bonus+self.onepair+self.twopair+self.threepair+self.fourpair+self.smalladder+self.bigladder+self.house+self.chance+self.yatzy
def add(self):
moment=input("Where do you want to put your points?: ") #ej klar
points=input("How many points did you get?: ")
self.lista
def visa(self):
for i in self.name:
print(i)
def welcome():
print("Welcome to the yahtzee game!")
players = int(input("How many players: "))
rounds=0
spelarlista=[]
spelarlista.append("name")
while not players==rounds:
player=input("What is your name?: ")
rounds=rounds+1
spelarlista.append(Player(player))
table_data = [spelarlista,
['Ettor',spelarlista[0].ones],
['Tvåor'],
['Treor'],
['Fyror'],
['femmor'],
['sexor']]
table = AsciiTable(table_data)
table.inner_row_border = True
table.table_data[0][0] += '\n'
print(table.table)
welcome()
I'm currently getting the errormessage "Str"-object has no attribute "ones". I understand that the line spelarlista[0].ones is not working, but let's say I ru the programme with the players "James" and "Anders", and I want my yatzy to print out the table with the players current score, how do I refer to that, let's say I did type "James" first, what do I write to get his points?
Thanks in advance!
spelarlista.append("name") means that the first item in your list is a string. Then later you try to access spelarlista[0].ones.
As the error message says, string objects do not have an attribute ones.

Efficient way to modify a .json file

I am trying to create a textgame in Python, and it is relying pretty heavily upon .json files. The most current problem is how to handle the picking up and dropping of items in the game. Conceptually, I think I can create a .json file containing player information (among them an inventory), update the inventory with the item's keyword, and delete that keyword from the room's .json file. I would do the opposite if the player were dropping an item.
My game.py:
import cmd
from room import get_room
from item import get_item
import textwrap
class Game(cmd.Cmd):
def __init__(self):
cmd.Cmd.__init__(self)
#Start the player out in Room #1 by calling the get_room() function
#passing the integer '1' with it, and reading 1.json.
self.loc = get_room(1)
# Displays the room to the player.
self.showRoom()
def move(self, dir):
#Grabs the direction the layer is moving, runs it through the
#_neighbor function within the room module. Determines if there
#is a room in that direction. If so, update to that new room an
#display it.
newroom = self.loc._neighbor(dir)
if newroom is None:
print("You can't go that way.")
else:
self.loc = get_room(newroom)
self.showRoom()
def showRoom(self):
#Displays the current room the player is in, as well as any other
#Objects within it. (Items, enemies, NPCs, etc)
print(self.loc.name)
print("")
#Wraps the text up to 70 words per line.
for line in textwrap.wrap(self.loc.description, 70):
print(line)
print("")
#Looks in the room's .json file to see if the room has a key to
#an item. If it does. Display it on the ground.
if self.loc.haveItem != "None":
print(self.loc.onGround)
print("")
#Looks to the room's .json file to see if the room has a key to
#'showNeighbors.' If it does, display the possible exits of that
#room.
print("Possible Exits:")
print(self.loc.showNeighbors)
def do_look(self, args):
#An exact copy of the showRoom function. There has to be a way to
#point do_look to showRoom() to keep from executing duplicate form.
#This is just bad form.
"""Reprints the rooms description and available exits."""
print(self.loc.name)
print("")
for line in textwrap.wrap(self.loc.description, 70):
print(line)
print("")
if self.loc.haveItem != "None":
print(self.loc.onGround)
print("")
print("Possible Exits:")
print(self.loc.showNeighbors)
def do_get(self, args):
#A function that handles getting an item off the room's ground.
#Currently not functioning as intended. Is meant to find the item
#In the room's .json file, use it to open the items .json file,
#and grab the 'keywords of said item. Then checks to see if
#get <keyword> was typed. If so, edit room's .json file to remove
#item from room, and add it to player inventory. Removing the
#.json file is neccessary to ensure item does not diplay in room
#once picked up.
"""type 'pick <item>' to pick up item in room."""
itemToTake = args.lower()
keywords = self.loc.keywords
if itemToTake == "":
print ("Take what? Type 'look' to see the items to take.")
return
if (itemToTake == keywords[0]) or (itemToTake == keywords[1]):
if self.loc.canTake == "True":
print("You have picked up a " + self.loc.itemName + ".")
#code should be placed here to wipe current room's .json
#file to ensure room is devoid of any items.
else:
print("That item is not here.")
def do_drop(self, args):
#A function that will handle dropping an item from a player's
#inventory. If an item is dropped in inventory, it will be removed
#from players .json inventory file, and added as a key:value
#to the room's .json file, so that should the player return, the
#item will load up as intended.
pass
def do_inv(self):
"""Opens up your inventory"""
#Hasen't been implimented yet. Would like to have it done through a
#.json file. The file would hold other players attributes such as:
#Hit Points, Strength, Dexterity, Armor Class, and the like.
#Self explainatory functions:
def do_quit(self, args):
"""Quit the game"""
print("Thank you for playing.")
return True
def do_n(self, args):
"""Goes North"""
self.move('n')
def do_s(self, args):
"""Goes South"""
self.move('s')
def do_e(self, args):
"""Goes East"""
self.move('e')
def do_w(self, args):
"""Goes West"""
self.move('w')
if __name__ == "__main__":
play = Game()
play.cmdloop()
my room.py:
import json
from item import get_item
"""
This module handles all of the rooms in the game. It searches for a .json file with the approriate id number, then opens it, reads it line by line, and stores it in a dictonary. The Room class then takes the information and sorts it out in to the corrisponding variables. If there is no string listed, it will list the default strings declared in the parameters.
"""
def get_room(id):
ret = None
with open(str(id) + ".json", "r") as file:
jsontext = file.read()
dictonary = json.loads(jsontext)
dictonary['id'] = id
ret = Room(**dictonary)
return ret
class Room():
def __init__(self, id = 0, name="A Room", description = "An Empty Room", neighbors = {}, showNeighbors = "None", haveItem = "None"):
#This is a mess. Has to be a better way to do all this rather than
#place it all in the initiate function. Function assigns .json file
# dictonaries to seperate variables. This is fine.
self.id = id
self.name = name
self.description = description
self.neighbors = neighbors
self.showNeighbors = showNeighbors
self.haveItem = haveItem
#This checks to see if room has an item. If so, grab it's .json file
#and assign it's values to variables. Fell that this SHOULD NOT be
#in __init__. Unsure how to do it any other way.
if haveItem != "None":
item = get_item(haveItem)
self.onGround = item.onGround
onGround = self.onGround
self.keywords = item.keywords
keywords = self.keywords
self.canTake = item.canTake
canTake = self.canTake
self.itemName = item.itemName
itemName = self.itemName
def modifiyRoom(self, id = 0, haveItem = "None"):
pass
#Function used to modify room .json files. uses include:
#Adding a dropped item.
#Removing an item dropped within room.
#Detect if enemy entered or left room.
#At least it would do all of that. If I can get it to work.
def _neighbor(self, direction):
if direction in self.neighbors:
return self.neighbors[direction]
else:
return None
def north(self):
return self._neighbor('n')
def south(self):
return self._neighbor('n')
def east(self):
return self._neighbor('n')
def west(self):
return self._neighbor('n')
and item.py:
import json
"""
This module handles all of the items in the game. It searches for a .json file with the approriate id, then opens it, reads it line by line, and stores it in a dictonary. The Item class then takes the information and sorts it out in to the corrisponding variables. If there is no string listed, it will list the default strings declared in the parameters.
"""
def get_item(itemName):
ret = None
with open(itemName + ".json", "r") as file:
jsontext = file.read()
item = json.loads(jsontext)
item['itemName'] = itemName
ret = Item(**item)
return ret
class Item():
def __init__(self, itemName = "", name = "An Item", onGround = "On ground", description = "A sweet Item", canTake = "False", keywords = "None", value = 0):
#Handles all of the variables found in an item's .json file.
#Feel this will have to act as a super class for more unique
#items, such as weapons, which will hold a damage value.
self.itemName = itemName
self.name = name
self.onGround = onGround
self.description = description
self.canTake = canTake
self.keywords = keywords
self.value = value
A sample room.json:
{"name" : "Disposal Room",
"description" : "A powerful burst of pain in your head wakes you up from your brief slumber, the intense throbbing causing you to see everything in a dull haze. It takes a few moments for the pain to die down, and with it your vision eventually returns to normal. After some examining you discover that you are in some sort of forgotten cell, the prison door to the west of you unlocked and slightly ajar.",
"neighbors" : {"s" : 2},
"showNeighbors" : "south",
"haveItem" : "sword"
}

having trouble writing dictionary list as a string

I'm trying to write a program that creates an address book with contact names, emails, phone numbers, etc. I store each contact as a dictionary and then place each person (dictionary) into a global list. I then convert the list to a string using repr() and write it to a file. When I try to reload the list and write what it contains, I get a list of empty dictionaries. Please help me figure out what is wrong.
Here is my code:
list = []
listfile = 'phonebook.txt'
class bookEntry(dict):
total = 0
def __init__(self):
bookEntry.total += 1
self.d = {}
def __del__(self):
bookEntry.total -= 1
class Person(bookEntry):
def __init__(self, n):
bookEntry.__init__(self)
self.n = n
print '%s has been created' % (self.n)
def addnewperson(self, n, e = '', ph = '', note = ''):
f = file(listfile, 'w')
self.d['name'] = n
self.d['email'] = e
self.d['phone'] = ph
self.d['note'] = note
list.append(self)
listStr = repr(list)
f.write(listStr)
f.close()
I start the program with a startup() function:
def startup():
aor = raw_input('Hello! Would you like to add an entry or retrieve one?')
if aor == 'add':
info = raw_input('Would you like to add a person or a company?')
if info == 'person':
n = raw_input('Please enter this persons name:')
e = raw_input('Please enter this persons email address:')
ph = raw_input('Please enter this persons phone number:')
note = raw_input('Please add any notes if applicable:')
X = Person(n)
X.addnewperson(n, e, ph, note)
startup()
I add these answers to the prompts:
'''
Hello! Would you like to add an entry or retrieve one?add
Would you like to add a person or a company?person
Please enter this persons name:Pig
Please enter this persons email address:pig#brickhouse.com
Please enter this persons phone number:333-333-3333
Please add any notes if applicable:one of three
Pig has been created
'''
When I open phonebook.txt, this is what I see:
[{}]
Why are empty dictionaries being returned?
You're deriving from dict, but storing all the elements in a member d. Hence, repr gives you a string representing an empty dict. If you want to use a bookEntry as a dict, insert the info with
self['name'] = n
instead of
self.d['name'] = n
(But really, you shouldn't be inheriting from dict here. Also, please don't use list as an identifier, it's the name of a builtin.)
you should save self.d instead of self:
alist.append(self.d)
listStr = repr(alist)
f.write(listStr)
btw don't use list as the name of a variable, you are overwritting the keyword list
Your problem is that the X.d dictionary is not the same as the dictionary "bookEntry" is inheriting from. Therefore repr(X) is not showing X.d
A solution might be to override repr in BookEntry:
e.g.
def __repr___(self):
return repr(self.d)

Categories

Resources