Loading CSV file to create objects of a class (Python, Jupyter Notebook) - python

I am try to build a database of all MLB and minor league baseball players. Keeping track of what teams they are on, transactions, and eventually statistics.
It is a huge database, and I'm not far along yet, but if the file shuts down in Jupyter Notebook I will lose all of the objects I made in my Player class (to create players). I am creating players in the Player class and then using functions to add them to a main dictionary (to make the process of adding easier and quicker). I am creating ID's for the object names, and including a value in the object as the same ID and index number from the dataframe. Then I filter out data to separate teams.
My question is, if I need to save and reload the information back into the Jupyter Notebook, is there any way I can load the same objects from the Player class? A lot of the system I built depends on being able to track the object names of each player and the index number of each player to update information and record information for each player. I included a little bit of my code...
Thanks for any information and help.
class Player:
def __init__(self, number, first, last, pos, cls, ht, wt, bat, throw, birthdate, organization, team, level):
self.number = number
self.first = first
self.last = last
self.pos = pos
self.cls = cls
self.ht = ht
self.wt = wt
self.bat = bat
self.throw = throw
self.birthdate = birthdate
self.age = (age(self.birthdate))
self.organization = organization
self.team = team
self.level = level
def addDirectory(playerid, ident, x, y, z, i):
playerid.id = ident
playerid.status = x
playerid.active = y
playerid.expanded = z
playerid.index = i
directory['ID'].append(playerid.id)
directory['First'].append(playerid.first)
directory['Last'].append(playerid.last)
directory['Age'].append(playerid.age)
directory['Organization'].append(playerid.organization)
directory['Team'].append(playerid.team)
directory['Level'].append(playerid.level)
directory['Position'].append(playerid.pos)
directory['Height'].append(playerid.ht)
directory['Weight'].append(playerid.wt)
directory['Bats'].append(playerid.bat)
directory['Throws'].append(playerid.throw)
directory['Status'].append(playerid.status)
if playerid.expanded == True:
directory['40-Man'].append('Yes')
else:
directory['40-Man'].append('No')
print(playerid.first + ' ' + playerid.last + ' added to Directory')
print(playerid.id + ' index number is: ' + str(playerid.index))

Related

Coding a group of interrelated objects which are updated upon addition or removal of an object in the group

So I have a group of N persons each having their own unique id. Each person has a randomized opinion of each already existing person ranging from 0 to 100. Upon the addition of a new person, I'd like all existing persons to acquire a randomized opinion of this new person. Upon removal of an existing person, I'd like all remaining persons to remove their opinion of the removed person.
Here's what I have up to now:
import random
persons = {}
class Person():
def __init__(self, idn):
self.idn = idn
self.opinions = {}
for i in persons:
self.opinions[i] = random.randrange(100)
persons[idn] = self
for i in persons:
persons[i].update()
def update(self):
pass
for i in range(20):
person_i = Person(i)
Now clearly the problem here is that only the last created object has opinions of all other persons. I was tinkering with creating a Person.update() function, but I have no clue how to proceed.
I was thinking, perhaps there is already somewhere a framework created to deal with this type of situation? (I would eventually hope to make even more complicated interrelations). The idea is having an object that holds a relationship to every other object in its group, and vice-versa for each other object in the group.
Any help is appreciated, especially resources to learn. I am a beginner at python.
Here for your reference, it is not working for more Person groups, just one Person group. If you need more groups, you have to specified group key for each person. If you want to del person, should person.delete() first.
import random
class Person():
table = {}
def __init__(self):
self.key = self.get_key()
self.opinions = {}
for key in Person.table:
self.opinions[key] = random.randrange(100)
for person in Person.table.values():
person.opinions[self.key] = random.randrange(100)
Person.table[self.key] = self
def get_key(self):
i = 0
while i in Person.table:
i += 1
return i
def delete(self):
del Person.table[self.key]
for person in Person.table.values():
del person.opinions[self.key]
del self
persons = [Person() for i in range(20)]

Call a "variable" from a function in Python?

I'm not even sure I'm calling those by their correct names but here's what I'm working with. I'm working on a simple hockey simulator that only uses math at this time to simulate the results of the games. Currently there is no names or anything like that and I've just generated a "list" of names for "team1" when the scorers are chosen. That's where this comes in. I want to create a list of players for each team and figured functions would be best...if its not please let me know an easier way. So here's the function right now:
def c1():
_name = "Jason Delhomme"
_overall = random.choice((6.00, 7.44, 8.91))
And the _overall variable would need to be called in some places whereas the _name variable would be called in another place. Is this possible?
tm1center = ((c1 * .5) + (c2 * .35) + (c3 * .15)) * 3
Instead of "c1" above I would replace that with _overall from the c1 function. I'm not sure how to do that or if its possible.. sorry for repeating myself here lol...
And then I have this (below) for the player list:
tm1players = ["player1", "player2", "player3", "player4", "player5"]
Ideally, I would replace all of those with the _name variable in each function. The player functions would also go into more depth with their speed, hands, shooting, etc. ratings as well. I don't know how sim sports handle this as I'm very new to coding (just started school) and I wrote the original engine in excel, which is why its just numbers and not physics or plays.
If this doesn't explain it well enough please let me know and I'll further explain what I'm trying to do.
In your case, its better to use a class and assign two variable to that class then create instances of it, for example:
class Player:
def __init__(self, name):
self.name = name
self.overall = random.choice((6.00, 7.44, 8.91))
player1 = Player('Jason Delhomme')
player2 = Player('Another Player')
tm1center = (player1.overall * .5) + (player2.overall * .35)
tm1players = [player1.name, player2.name]
EDIT:
to add overall when creating the class you need to change the init method to :
def __init__(self, name, overall):
self.name = name
self.overall = overall
then pass it when creating the class:
player1 = Player('Player Name', 6.23)
You can create a list of players at start and append each instance of player to that list for future use, for example:
player_list = []
player1 = Player('Player Name', 5)
player_list.append(player1)
player2 = Player('Player2 Name', 2.5)
player_list.append(player2)
# dynamically create tm1players and tm1center
tm1players = [x.name for x in player_list]
tm1center = [x.overall for x in player_list]
You have to read about object oriented programming, and then start working with classes, methods, and from that creating objects. This is an example for using different functions (methods) under the umbrella of a Class. Note how the use of self is necessary for accessing variables between the different methods:
ClassHockey():
def __init__(self):
self.description = "in here you would define some 'you always use'
variables"
def c1(self):
self._name = "Jason Delhome"
self._overall = random.choice((6.00, 7.44, 8.91))
def c2(self):
self._new_name = self._name + "Jefferson"
return self._new_name
hockeyName = ClassHockey()
hockeyName.c2()
If you run this you'll get the _new_name "Jason Delhome Jefferson", and you can apply this example to all kinds of operations between your class methods.
While manually creating a class is a great solution for this problem, I believe that generating one via collections.namedtuple could also work in this senario.
from collections import namedtuple
import random
Player = namedtuple("Player", "name overall")
player1 = Player("Jason Delhomme", random.choice((6.00, 7.44, 8.91)))
player1 = Player("Other Name", random.choice((6.00, 7.44, 8.91)))
final_overall = (player1.overall * .5) + (player2.overall * .35)
Using list comprehension, you could built your entire team:
list_of_players = [Player(input("Enter player: "), random.choice((6.00, 7.44, 8.91))) for i in range(5)]
tm1center = ((list_of_players[0].overall * .5) + (list_of_players[1].overall * .35) + (list_of_players[2].overall * .15)) * 3
Python lets you group info and data together using classes. In your case, you mostly have information about each player, like a name and various stats. You could define a class like:
class Player:
def __init__(self, name):
self.name = name
self.overal = random.choice((6.00, 7.44, 8.91))
Now you can create a bunch of objects from the class:
c1 = Player("player1")
c2 = Player("player2")
c3 = Player("player3")
And you could calculate
tm1center = ((c1.overall * .5) + (c2.overall * .35) + (c3.overall * .15)) * 3
Since you already have a list of player names, you can use a list comprehension to get a list of players in one step:
tm1players = ["player1", "player2", "player3", "player4", "player5"]
tm1 = [Player(name) for name in tm1players]
Now you can access each element in that list, and get their name and overall attributes to do with them as you see fit.
If you want to extend the tm1center1 calculation to include all five players now, you can assign a weight to each one:
class Player:
def __init__(self, name, weight):
self.name = name
self.weight = weight
self.overal = random.choice((6.00, 7.44, 8.91))
tm1center = sum([p.overall * p.weight for p in tm1]) * len(tm1)
where tm1 is defined something like:
tm1players = ["player1", "player2", "player3", "player4", "player5"]
tm1weights = [0.5, 0.3, 0.05, 0.1, 0.05]
tm1 = [Player(name, weight) for name, weight in zip(tm1players, tm1weights)]
Python is a pretty flexible language. Go crazy with it!

How do I dynamically name an instance or change the attributes of all instances in a class?

I am trying to model population growth using individual agents, but have already run into trouble with the basic skeleton of the model.
I have a class to hold individuals
class Individual:
"""These are individuals"""
list = []
def __init__(self, name, sex, dob):
self.name = name
self.sex = sex
self.dob = dob
self.list.append(name)
def __str__(self):
return "name is {}, sex is {}, age is {}" .format(self.name, self.sex, curyear - self.dob)
and I instantiate new individuals through
def birth():
global person
person = Individual((next(name)), randsex(), curyear)
The basic growth loop is
for i in range(totalyears):
curyear = curyear + 1
if curyear - person.dob == 18:
birth()
else:
pass
The problem seems to be that
if curyear - person.dob == 18:
birth()
is only ageing and checking the last instance of Individual that's created.
print (Individual.list) shows that my final population = starting population + total years /18 and print (str(person)) too seems to confirm this.
I think this is because my birth() function basically names each new instance 'person', so whenever I use person.whatever it references the latest instance created. It seems to me that there are two possibilities.
A) Dynamically give each new instance a unique name, and use a list to reference each of these instances' attributes in the growth loop.
B) Add an age instance attribute and figure out how to change this for all members of the class.
I don't know if either is possible, or how to do them. I would appreciate any advice and examples!

Python libtcod: Object description feature error

I'm working my way through the libtcod python tutorial, I've decided to mess around with some of the code to make it more unique today, and decided to start off with a feature to allow the player to hover the mouse over an object and press 'd' for a description of that object.
I'm currently running into an attribute error: 'str' object has no attribute 'describe' line 657. I've tried many different things but notihng seems to work, unfortunately my level of understanding is pretty limited right now so I can't figure out what's going wrong.
Here are the relevant classes and functions:
class Object:
#this is a generic object: the player, a monster, an item, the stairs...
#it's always represented by a character on screen.
def __init__(self, x, y, char, name, color, blocks=False, fighter=None, ai=None, item=None, description=None):
self.x = x
self.y = y
self.char = char
self.name = name
self.color = color
self.blocks = blocks
self.fighter = fighter
if self.fighter: #let the fighter component know who owns it
self.fighter.owner = self
self.ai = ai
if self.ai: #let the ai component know who owns it
self.ai.owner = self
self.item = item
if self.item: #let the item component know who owns it, like a bitch
self.item.owner = self
self.description = self
if self.description: #let the description component know who owns it
self.description.owner = self
def describe(self):
#describe this object
message(self.description, libtcod.white)
def handle_keys():
global keys;
if key_char == 'd':
#show the description menu, if an item is selected, describe it.
chosen_object = description_menu('Press the key next to an object to see its description.\n')
if chosen_object is not None:
chosen_object.describe()
return 'didnt-take-turn'
def description_menu(header):
global mouse
#return a string with the names of all objects under the mouse
(x, y) = (mouse.cx, mouse.cy)
#create a list with the names of all objects at the mouse's coordinates and in FOV
names = [obj.name for obj in objects if obj.x == x and obj.y == y and libtcod.map_is_in_fov(fov_map, obj.x, obj.y)]
names = ', '.join(names) #join the names, seperated by commas
return names.capitalize()
#show a menu with each object under the mouse as an option
if len(names) == 0:
options = ['There is nothing here.']
else:
options = [item.name for item in names]
index = menu(header, options, INVENTORY_WIDTH)
#if an item was chosen, return it
if index is None or len(names) == 0: return None
return names[index].description
Any help would be much appreciated!
The function description_menu() has the following return
names[index].description
This is a string member that belongs to Object.
When you say
chosen_object.describe()
You are calling the describe() method, but that belongs to the Object class, not a string (hence the attribute error: 'str' object has no attribute 'describe'). You would have to have description_menu() return the Object instead of just the name of it.

Simple OOP query. Python: saving object names in __init__

As close to the title as possible. I am very new to OOP (and coding in general) and would like to create a program that plays Blackjack. I want to save the objects I create into a list automatically so once it's created I can use the list to cycle through them (I want to create player objects, but save the variable names (right word???) to a list so once it's created using user input I can automatically access them.
So far I've built this:
ROSTER = []
class Player():
"""player in the game"""
def __init__(self, name, score= 0):
self.name = name
self.score = score
ROSTER.append(self.name)
But of course this only gives me the names put into the variable self.name... how can I capture the variable names (right term once again?). self.name won't (afaik) let me access the individual objects via:
excuse the crap formatting plz. =/
Also, if I'm using the wrong terms plz correct me. Learning on your own is kinda hard as far as mastering all the terms.
EDIT: sorry, my post was confusing. The code I posted was meant to show a dead end, not what I am looking for, and my terminology is pretty bad (I feel like a foreigner most of the time). When I said variable names, I think I should have said 'object names' (?) so:
p1 = Player("bob")
p2 = Player("sue")
I want ["p1","p2"] (or if a string format will give me problems when I try to call them, whatever the appropriate way is.)
Once again, sorry for the super confusing first post. Hopefully this edit is a little clearer and more focused.
You could put self in the roster instead. I.e.:
ROSTER = []
class Player():
def __init__(self, name, score = 0):
self.name = name
self.score = score
ROSTER.append(self)
Then you would use the ROSTER list like this:
>>> p1 = Player("Jane")
>>> p2 = Player("John")
>>> ROSTER
[<__main__.Player instance at 0x10a937a70>, <__main__.Player instance at 0x10a937a28>]
>>> for p in ROSTER:
... print p.name, p.score
...
Jane 0
John 0
Or, perhaps better, you could make ROSTER a dictionary:
ROSTER = dict()
class Player():
def __init__(self, name, score = 0):
self.name = name
self.score = score
ROSTER[self.name] = self
That way you can access the player objects by name using ROSTER[name], and you can cycle through them with ROSTER.values(). For example:
>>> p1 = Player("Jane")
>>> p2 = Player("John")
>>> print ROSTER["Jane"].name, ROSTER["Jane"].score
Jane 0
>>> print ROSTER["John"].name, ROSTER["John"].score
John 0
>>> for p in ROSTER.values():
... print p.name, p.score
...
Jane 0
John 0
Are you talking about this?
ROSTER = []
class Player():
def __init__(self, name, score= 0):
self.name = name
self.score = score
ROSTER.append(self)
a=Player('Jack',100)
b=Player('Blackk',1000)
c=Player('Mike')
for x in ROSTER:
print(x.name,x.score)
output:
Jack 100
Blackk 1000
Mike 0

Categories