I really hope this is not a repeat...if it is, I can't find an answer anywhere, so I apologize.
Anyways, my question is, I'm writing code where, if the data I get requires a team instead of a player, I have a class (called Team) that holds two SinglePlayers (also a class), and then a few other attributes, just strings. The problem is, when I iterate through my loop, reading the xml data and filling up my "team" variable, it seems that all the info for the SinglePlayers doesn't get reset. This is a problem, because it is is changing that info every time I insert a new "team" into the list of "team" objects I have. The code is long, so I'm only going to post what's relevant.
I have only been working with python again for a few days. I have been working the past year in java and c++ so my brain has those concepts in my head of how variables and structures work. I know python is different, so if someone could please clarify why this doesn't work, that would be amazing. Thanks!
class SinglePlayer:
entry_code = ""
first_name = ""
last_name = ""
nation = ""
seed_rank_sgl = ""
seed_rank_dbl = ""
entry_rank_sgl = ""
entry_rank_dbl = ""
class Team:
top_player = SinglePlayer()
bottom_player = SinglePlayer()
entry_code = ""
seed_rank = ""
entry_rank = ""
def DoublesEvent(self, team_nodes):
#Create List to store team objects
teams_list = []
for k in range(0, team_nodes.length):
#Get the current node
teams_node = team_nodes.item(k)
team_node = team_nodes.item(k).getElementsByTagName("Player")
top_player_node = team_node.item(0)
bottom_player_node = team_node.item(1)
#Make a new team object to fill and add to teams_list
team = Team()
team.entry_code = teams_node.getAttribute("EntryCode")
#Top Player Info
team.top_player.first_name = top_player_node.getAttribute("FirstName")
team.top_player.last_name = top_player_node.getAttribute("LastName")
team.top_player.nation = top_player_node.getAttribute("Nation")
#Bottom Player Info
team.bottom_player.first_name = bottom_player_node.getAttribute("FirstName")
team.bottom_player.last_name = bottom_player_node.getAttribute("LastName")
team.bottom_player.nation = bottom_player_node.getAttribute("Nation")
eam.seed_rank = self.GetSeedRank(team)
team.entry_rank = self.GetEntryRank(team)
#Add the team to the list
teams_list.append(team)
return teams_list
Your class holds a reference to two SinglePlayer() instances, not your instances. Use a __init__ method to create new instances for every Team instance:
class Team:
entry_code = ""
seed_rank = ""
entry_rank = ""
def __init__(self):
self.top_player = SinglePlayer()
self.bottom_player = SinglePlayer()
As it happens, because you rebind each of the string attributes on the instances you create, you happen to create instance attributes for those. You'd be better off moving those into __init__ as well and making their relationship as instance attributes explicit:
class Team:
def __init__(self):
self.entry_code = ""
self.seed_rank = ""
self.entry_rank = ""
self.top_player = SinglePlayer()
self.bottom_player = SinglePlayer()
and do the same for your SinglePlayer class.
Related
w_rook_1 = ChessPiece('w_rook_1')
w_knight_1 = ChessPiece('w_knight_1')
w_bishop_1 = ChessPiece('w_bishop_1')
w_king = ChessPiece('w_king')
w_queen = ChessPiece('w_queen')
w_bishop_2 = ChessPiece('w_bishop_2')
w_knight_2 = ChessPiece('w_knight_2')
w_rook_2 = ChessPiece('w_rook_2')
w_pawn_1 = ChessPiece('w_pawn_1')
w_pawn_2 = ChessPiece('w_pawn_2')
w_pawn_3 = ChessPiece('w_pawn_3')
w_pawn_4 = ChessPiece('w_pawn_4')
w_pawn_5 = ChessPiece('w_pawn_5')
w_pawn_6 = ChessPiece('w_pawn_6')
w_pawn_7 = ChessPiece('w_pawn_7')
w_pawn_8 = ChessPiece('w_pawn_8')
Is there an easier way to do this? I would also like to be able to use the objects afterwards.
Here is a simple approach using a dictionary when dealing with this type of challenge.
I added some comments within the code, please read.
instance_names = ['w_rook_1',
'w_knight_1',
'w_bishop_1',
'w_king',
'w_queen',
'w_bishop_2',
'w_knight_2',
'w_knight_2']
class ChessPiece(object):
def __init__(self, name):
self.name = name
self.move = "moving {}".format(name)
chess_objs = {}
for obj in instance_names:
# insert instance names ex. 'w_rook_1' as the key
# the ChessPiece instance is set as the value
chess_objs.setdefault(obj, ChessPiece(obj))
# here just illustrates how to access fields
# bound to each object
print(chess_objs['w_bishop_1'].name)
print(chess_objs['w_bishop_1'].move)
outputs:
w_bishop_1
moving w_bishop_1
If you follow #kaya3's advice and redesign your ChessPiece class, you could use a list comprehension easily, something like this (using abbreviations and ignoring number):
color = 'W'
non_pawns = [ChessPiece(color, c) for c in 'RNBKQBNR']
pawns = [ChessPiece(color, 'P') for _ in range(8)]
I have created a script that stores and edits meta-data in a system. I am now cleaning up my code by defining a class and methods, previously I only used separate functions.
In the script I am storing old and new values of certain types of metadata in lists, which I print out after the script has completed its run. I have defined multiple lists (16 to be exact), which I realized is quite a lot when passing them through a method. I was wondering what is the most pythonic way to approach this.
These are the following list variables that i define in the beginning. In the function/method I append values to them. In the end I print the stored valued out as a report.
split_name = []
split_name_new = []
name = []
name_new = []
meta = []
meta_new = []
series = []
series_new = []
product = []
owner = []
desc = []
desc_new = []
keywords = []
keywords_new = []
no_edit_page =[]
no_edit_page_name = []
In a class i figured it will look something like (if I define all the list separately)
class Metadata_editor():
def __init__(self,url):
self.split_name = []
self.split_name_new = []
self.name = []
self.name_new = []
self.meta = []
self.meta_new = []
self.series = []
self.series_new = []
self.product = []
self.owner = []
self.desc = []
self.desc_new = []
self.keywords = []
self.keywords_new = []
self.no_edit_page =[]
self.no_edit_page_name = []
#Ugly solution because the method gets crowded by all the variables passed through
def data_edit(self, split_name, split_name_new, name, name_new,.. etc):
#Not the whole method, but just to give some idea..
#Selenium function that locates meta
md = driver.find_element_by_xpath("//input[#name='metadata-name']")
meta_data = md.get_attribute("value")
#replace_words translate the word using a dictionary object
meta_data_new = replace_words(meta_data,c)
meta.append(meta_data)
meta_new.append(meta_data_new)
The solution above I realized would not be ideal.
I found an alternative way that I could use, which is I define a list of lists. The solution would then look something like this (see below). However 'data_list[10]' is not as self-explanatory as for say 'owner'. My question is, is this the 'best' way to solve this, or do you have any other suggestions? I don't really have anything against this solution, but was wondering if there is a more 'pythonic' way to approach this.
class Metadata_editor():
def __init__(self,url):
self.data_list=[[] for _ in range(16)] #Creates a list, that contains 16 lists
# More eloquent solution, as only one variable is passed through. However finding
# the right data from data_list is perhaps not as easy before
def data_edit(self, data_list):
md = driver.find_element_by_xpath("//input[#name='metadata-name']")
meta_data = md.get_attribute("value")
meta_data_new = replace_words(meta_data,c)
data_list[5].append(meta_data)
data_list[6].append(meta_data_new)
You could store it as a dictionary. That would have the advantage of being able to reference the keys by name rather than having to remember the indexes.
class Metadata_editor():
def __init__(self, url):
keys = [
'split_name', 'split_name_new', 'name', 'name_new' 'meta', 'meta_new',
'series', 'series_new', 'product', 'owner', 'desc', 'desc_new',
'keywords', 'keywords_new', 'no_edit_page', 'no_edit_page_name',
]
self.data_dict = dict((x, []) for x in keys)
def data_edit(self):
md = driver.find_element_by_xpath("//input[#name='metadata-name']")
meta_data = md.get_attribute("value")
meta_data_new = replace_words(meta_data,c)
self.data_dict['meta'].append(meta_data)
self.data_dict['meta_new'].append(meta_data_new)
A few extra points to note:
class names generally follow the UpperCaseCamelCase convention. So Metadata_editor would more conventionally be written as MetadataEditor
Using self sets an attribute on the class, it can be accessed in the class using self and the attribute does not need to be passed into the method. I have shown this in the example above, accessing self.data_dict in the data_edit method.
You can also use setattr to set attributes to the class as shown in some of the other answers.
You can initialize multiple lists as below:
class Metadata_editor():
def __init__(self,list_names):
[setattr(self,name,[]) for name in list_names]
me = Metadata_editor(['split_name','split_name_new']) # initialize two lists
me.split_name.append(5) # add value to a list
print(me.split_name, me.split_name_new)
>>[5], [ ]
Once set as part of the class via self.list_name, the list(s) can be accessed globally within the class - no longer requiring to be 'passed in'. To initialize lists to specific values, you can do:
def __init__(self,list_names,list_values):
[setattr(self,name,value) for name,value in zip(list_names,list_values)]
Use setattr:
...
def __init__(self, url):
names = '''split_name split_name_new name
name_new meta meta_new series series_new
product owner desc desc_new keywords
keywords_new no_edit_page
no_edit_page_name'''.split()
for name in names:
setattr(self, name, [])
...
I am getting this error each time I try to run this app in its present state.
TypeError: cannot concatenate 'str' and 'GameData' objects
I am trying to get a data object from my Game(GameData) class onto the browser with my html. It's a subclass of GameData() which is a template class.
class GameData(object): #This class is the template for the data for each game.
def __init__(self):
self.title = ''
self.genre = ''
self.description = ''
self.developer = ''
self.rating = ''
self.image = ''
class Game(GameData): #Thas class holds all the data for each game.
def __init__(self):
#object for Castlevania
self.castlevania = GameData()
self.castlevania.title = 'Castlevania'
self.castlevania.genre = 'Action Platformer'
self.castlevania.description = 'Released in 1986 in Japan, Castlevania for the NES and Famicom Disc System spawned a series rich in action as well as exploration. This first game was merely a simple platformer but it inspired many changes to the formula over the years and invented the "Metroidvania" genre.'
self.castlevania.developer = 'Konami'
self.castlevania.rating = '7.5/10'
self.castlevania.image = 'images/t_castlevania.png'
There are other objects but if I can get one of them to work I can figure out the rest. I need it to get into this elif statement highlighted with a comment.
class MainHandler(webapp2.RequestHandler):
def get(self):
i = Intro()
d = GameData()
g = Game()
if self.request.GET:
page = self.request.GET['page']
if page == 'main_page':
self.response.write(i.head + i.main_page + i.main_title + i.main_links)
elif page == 'castlevania': #The data needs to go in this concatenation.
self.response.write(i.head + i.main_page + i.castlevania + (the data object should go here) + i.main_links)
From there I know what to do. I just need to know how to convert the data into a string so I can concatenate it. If anyone can help I would appreciate it. Also I tried using an array for the objects but that didn't work for me either.
You just need to include the __str__ function in your Game(GameData) class.
eg.
def __str__(self):
# Here you would put whatever logic in terms of returning a string
# representation of your game object. Eg:
return self.castlevania.title
Then, you would simply call str(g) where g is your Game(GameData) object
I am trying to print a list of python objects that contain a list as a property and i am having some unexpected results:
here is my code:
class video(object):
name = ''
url = ''
class topic(object):
topicName = ''
listOfVideo = []
def addVideo(self,videoToAdd):
self.listOfVideo.append(videoToAdd)
def getTopic(self):
return self.topicName
def getListOfVideo(self):
return self.listOfVideo
topic1 = topic()
topic1.topicName = 'topic1'
video1 = video()
video1.name = 'VideoName1'
video1.url = 'VideoURL1'
video2 = video()
video2.name = 'VideoName2'
video2.url = 'VideoURL2'
topic1.addVideo(video1)
topic1.addVideo(video2)
topic2 = topic()
topic2.topicName = 'topic2'
video3 = video()
video3.name = 'VideoName3'
video3.url = 'VideoURL3'
video4 = video()
video4.name = 'VideoName4'
video4.url = 'VideoURL4'
topic2.addVideo(video3)
topic2.addVideo(video4)
topicsList = []
topicsList.append(topic1)
topicsList.append(topic2)
for topicCurrent in topicsList:
print(topicCurrent.topicName)
for video in topicCurrent.getListOfVideo():
print(video.name)
print(video.url)
What I expect to get is this:
topic1
VideoName1
VideoURL1
VideoName2
VideoURL2
topic2
VideoName3
VideoURL3
VideoName4
VideoURL4
but what I actually get is this:
topic1
VideoName1
VideoURL1
VideoName2
VideoURL2
VideoName3
VideoURL3
VideoName4
VideoURL4
topic2
VideoName1
VideoURL1
VideoName2
VideoURL2
VideoName3
VideoURL3
VideoName4
VideoURL4
Why? I want to iterate over my list of topics and print out each video in each topic, but for each topic it prints out all videos???
What is going on here?
You have created class variables instead of instance variables, which are different for each instance object. Define your class as follows:
class topic(object):
def __init__(self):
self.topicName = ''
self.listOfVideo = []
def addVideo(self,videoToAdd):
self.listOfVideo.append(videoToAdd)
def getTopic(self):
return self.topicName
def getListOfVideo(self):
return self.listOfVideo
From Python Tutorial:
Instance variables are for data unique to each instance and class
variables are for attributes and methods shared by all instances of
the class.
EDIT:
One more important thing to consider is that why only listOfVideo was common for all instances but not topicName. It is because list's are mutable objects while string's are immutable.
So any changes made to listOfVideo are common for all instances, i.e., they still refer to listOfVideo defined in the topic namespace.
However when you do topic1.topicName = 'topic1', you create a new variable topicName within topic1 namespace, which overrides the topicName found in topic(class) namespace. You can confirm it by printing the value topic.topicName, which you will find to be an empty string, i.e., ''.
guys i have a problem with my variable.
When i instance my class my variable dossierProd and dossierModif is not empty but when i want use another function she is empty.
import glob
class OBDI:
dossierProd = ""
dossierModif = ""
listeFichierProd = []
listeFichierModif = []
def __init__(self, dossierP, dossierM):
dossierProd = dossierM
dossierModif = dossierM
def recupListeFichier(self):
HERE MY VARIaBLE dossierProd & dossierModif as empty
for fichier in glob.glob(str(self.dossierProd) + '*.csv'):
self.listeFichierProd.append(fichier.replace("\\", "/"))
for fichier in glob.glob(str(self.dossierModif) + '*.csv'):
self.listeFichierModif.append(fichier.replace("\\", "/"))
if len(self.listeFichierProd) != len(self.listeFichierModif):
print "toto
Have you got an idea why my variable is empty ?
Thx to your response.
Sorry for my bad english ;)
Oh thanks, this error is so stupid.
I'm to be accustomed to java
You haven't initialized dossierP and dossierM instance variables in __init__():
def __init__(self, dossierP, dossierM):
self.dossierProd = dossierM
self.dossierModif = dossierM
Watch self. here.
Also, since it appears that dossierProd and dossierModif variables make sense only for when you have an instance of a OBDI class, remove dossierProd = "" and dossierModif = "" lines.
Also, you probably don't want to share listeFichierProd and listeFichierModif lists between OBDI class instances - initialize lists in __init__():
def __init__(self, dossierP, dossierM):
self.dossierProd = dossierM
self.dossierModif = dossierM
self.listeFichierProd = []
self.listeFichierModif = []
and remove listeFichierProd = [] and listeFichierModif = [] lines.
Make sure you understand what is discussed in the following threads:
Instance variables vs. class variables in Python
python class instance variables and class variables
Hope that helps.