check if an attribute of a class is assigned to a instance - python

i'm making a little game for fun and i ran into an issue, how can i see if the email of a member is assigned to a instance?
file1:
if "test1#gmail.com" in file2:
print("ok"
else:
print("not ok")
file2:
player1 = Player("testName1", "test1#gmail.com", "testpwd1"
player2 = Player("testName2", "test2#gmail.com", "testpwd2"
player3 = Player("testName3", "test3#gmail.com", "testpwd3"
player4 = Player("testName4", "test4#gmail.com", "testpwd4"

overriding the __contains__ method will do the trick.
So:
def __contains__(self, key):
return key in self.email
Edit:
If for some reason you don't care which attribute contains the value, this will work:
def __contains__(self, key):
return key in list(self.__dict__.values())

If you put Players in a list then you could use a dictionary to index that list. This example lets you look up by name and email at the same time.
file2.py
class Player:
def __init__(self, name, email, pwd):
self.name = name.lower()
self.email = email.lower()
self.pwd = pwd
players = [
Player("testName1", "test1#gmail.com", "testpwd1"),
Player("testName2", "test2#gmail.com", "testpwd2"),
Player("testName3", "test3#gmail.com", "testpwd3"),
Player("testName4", "test4#gmail.com", "testpwd4")
]
# index to lookup up player by name or email
player_index = {player.name:player for player in players}
player_index.update({player.email:player for player in players})
file1.py
import file2
if file2.player_index.get("test1#mail.com".lower(), None) is not None:
print("ok")
else:
print("not ok")
It would be common to place that players list in some other data structure like a CSV file or even a pickled file. Assuming you want to update players dynamically, it becomes awkward to represent them as class instances in a .py file. But that's an enhancement for another time.

Related

Video game save/load problems with python pickle (not loading instances)

I'm currently working on a text adventure in python (this language just because it's the one I know), and I'm finding that creating and loading savefiles removes some of the mecahnics I've made. I'll include the problematic code here, rather than all of elements that work fine. it's mainly to do with classes and how instances are 'pickled'.
Here are some of the classes I've created:
class Player:
def __init__(self, name):
self.sack = []
self.kit = []
self.equipped = []
self.log = []
self.done = []
class Weapon:
def __init__(self, name, price, minattack, maxattack):
self.name = name
self.price = price
self.minattack = minattack
self.maxattack = maxattack
class Food:
def __init__(self, name, price, healthadd):
self.name = name
self.price = price
self.healthadd = healthadd
class Quest:
def __init__(self, name, requirement, num, gold, npc, place, give_text, prog_text, comp_text, done_text):
self.name = name
self.requirement = requirement
self.num = num
self.score = 0
self.gold = gold
self.npc = npc
self.place = place
self.give_text = give_text
self.prog_text = prog_text
self.comp_text = comp_text
self.done_text = done_text
The instances in the Player class I've included here are just the ones that are appended by other mechanics with Weapons, Food and Quests. The code includes regions where Weapons, Food and Quests are populated (though working on a separate assets file might tidy things up a bit).
Here's how the save/load functions work currently:
def save(lastplace):
clear()
with open('savefile', 'wb') as f:
PlayerID.currentplace = lastplace.name
pickle.dump(PlayerID, f)
print("Game saved:\n")
print(PlayerID.name)
print("(Level %i)" % (PlayerID.level))
print(lastplace.name)
print('')
option = input(">>> ")
goto(lastplace)
def load():
clear()
if os.path.exists("savefile") == True:
with open('savefile', 'rb') as f:
global PlayerID
PlayerID = pickle.load(f)
savedplace = PlayerID.currentplace
savedplace = locations[savedplace]
goto(savedplace)
else:
print("You have no save file for this game.")
option = input('>>> ')
main()
It's worth noting that upon entry to the game, PlayerID (you) becomes a global variable. You might begin to see some of the issues here, or rather the overarching issue. Essentially, the pickling process serialises all of the possible class types stored in lists within the class of Player just get appended by their names, thus removing their class properties when loaded back into the game.
Is there a pythonic way to ensure that class instances are saved for a future load so that they can still behave as classes, particularly when stacked inside the class of Player? I appreciate this is more of an editorial rather than a question by its length, but any help would be hugely appreciated.

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

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

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"
}

How do i store multiple object attibutes to a single dictionary key?

I'm fairly new to the world of python and programming in general, and its rare that i get up the nerve to ask questions, but I'm stomped so i thought id suck it up and ask for help.
I'm making an Address book.
class Person():
def __init__(self,name,number,email):
self.name = name
self.number = number
self.email = email
contact = Person('Mike','1-800-foo-spam','email#email.com')
My question is how would go about storing all these attributes in a dictionary with contact.name as the key and contact.number and contact.email as the values.
Bonus question.
Should the dictionary be outside the class, perhaps in the main function?
or
Does it need to be a class variable(not completely sure how those work)
or an object variable
something like
self.storage = {}
Any help would be greatly appreciated.
Thank you!
If I put this information in a dictionary, I would do it like that:
class Person():
def __init__(self,name,number,email):
self.name = name
self.number = number
self.email = email
self.storage = {self.name: [self.number, self.email]}
def getStorage(self):
return self.storage
contact = Person('Mike','1-800-foo-spam','email#email.com')
print contact.storage
# or
print contact.getStorage()
But the whole idea of a dictionary is to have a number of keys and corresponding values. In this example, it always will be one only. So, another schema comes to my mind:
class Person():
def __init__(self,name,number,email):
self.name = name
self.number = number
self.email = email
# creating some example contacts
c1 = Person('Mike','1-800-foo-spam','email#email.com')
c2 = Person('Jim','1-700-foo-spam','e111mail#email.com')
c3 = Person('Kim','1-600-foo-spam','e222mail#email.com')
# creating a dictionary to fill it with c1..cn contacts
contacts = {}
# helper function to automate dictionary filling
def contactToDict(list_of_contacts):
for item in list_of_contacts:
contacts[item.name] = (item.number, item.email)
contactToDict([c1, c2, c3])
"""
expected output:
Mike: ('1-800-foo-spam', 'email#email.com')
Jim: ('1-700-foo-spam', 'e111mail#email.com')
Kim: ('1-600-foo-spam', 'e222mail#email.com')
"""
for key, val in contacts.items():
print str(key) + ": " + str(val)
The answer to the title of the question: a value should be a type of object with allows to have a "list" inside (i.e. list, tuple, another dictionary or custom type object having a number of attributes.)
You can pretty easily have a dictionary with tuples as the values.
a = {}
a["bob"] = ("1-800-whatever","bob#gmail.com")
If you wanted to make it a class variable, you'd just need to create an empty dictionary as part of the Person class:
class Person():
storage = {}
Then in __init__ you can store the new person's info in that dictionary:
def __init__(self,name,number,email):
self.name = name
self.number = number
self.email = email
Person.storage[name] = (number, email)
As you can see class attributes are accessed with the classname, but otherwise like any other attribute. You could store them as a tuple or a list if you need to update them. However if you intend to make changes, it might be better to store the actual Person object, to save having to update Person.storage and the actual person at the same time. This is even easier to do:
def __init__(self,name,number,email):
self.name = name
self.number = number
self.email = email
Person.storage[name] = self
self refers to the instance of Person that's being created with __init__. That's Mike in your example. Then you could access their values by attribute:
Person.storage["Mike"].number
Also as Kevin pointed out in a comment you might want to detect if the key already exists to avoid overwriting an old entry (eg. if there's already a Mike in the dictionary):
self.email = email
if name in Person.storage:
# Make unique name
Person.storage[name] = (number, email)

Categories

Resources