Edit: Solved. Thanks for the help guys, but it appears that the problem was that the list was overwritten and transformed into a sprite group, rendering all list manipulations useless.
I have recently started programming in python (always sets off the alarm bells), so I apologise if the way I've coded things is slightly scary. This particular program imports pygame (the 'engine' being used).
I'm attempting to create a list which contains objects / sprites. This I seem to have achieved, however, I have a problem removing an object from this list once it is no longer needed, as the object does not have a specific pointer as far as I can tell.
The sprite class is constructed as following;
class Point(pygame.sprite.Sprite):
def __init__(self,pos=(0,0)):
pygame.sprite.Sprite.__init__(self)
#Unimportant code
self.dead=False
print self
#This prints; "<Point sprite(in 0 groups)>"
def update(self):
if(self.dead):
#sprList_PointSet.remove(?)
pass
The objects and the list is created;
sprList_PointSet=[]
sprList_PointSet+=[Point((50,90))]
sprList_PointSet+=[Point((65,110))]
# ...
print sprList_PointSet
#This prints; [<Point sprite(in 0 groups)>, <Point sprite(in 0 groups)>, ...]
Is there a way to remove an instance from the list when it is no longer needed using .remove(x) in a case where there is no apparent memory indicator? If not / or / and could someone recommend a better way of doing such.
You can use weak references to let an instance disappear when nothing "important" needs it anymore.
self points to the object you want to remove, so just remove(self):
def update(self):
if self.dead:
try:
sprList_PointSet.remove(self)
except ValueError:
pass
remove is defined for mutable sequences, and is described in the tutorial:
Remove the first item from the list whose value is x. It is an error if there is no such item.
Related
I am trying to write a testing program for a python program that takes data, does calculations on it, then puts the output in a class instance object. This object contains several other objects, each with their own attributes. I'm trying to access all the attributes and sub-attributes dynamically with a one size fits all solution, corresponding to elements in a dictionary I wrote to cycle through and get all those attributes for printing onto a test output file.
Edit: this may not be clear from the above but I have a list of the attributes I want, so using something to actually get those attributes is not a problem, although I'm aware python has methods that accomplish this. What I need to do is to be able to get all of those attributes with the same function call, regardless of whether they are top level object attributes or attributes of object attributes.
Python is having some trouble with this - first I tried doing something like this:
for string in attr_dictionary:
...
outputFile.print(outputclass.string)
...
But Python did not like this, and returned an AttributeError
After checking SE, I learned that this is a supposed solution:
for string in attr_dictionary:
...
outputFile.print(getattr(outputclass, string))
...
The only problem is - I want to dynamically access the attributes of objects that are attributes of outputclass. So ideally it would be something like outputclass.objectAttribute.attribute, but this does not work in python. When I use getattr(outputclass, objectAttribute.string), python returns an AttributeError
Any good solution here?
One thing I have thought of trying is creating methods to return those sub-attributes, something like:
class outputObject:
...
def attributeIWant(self,...):
return self.subObject.attributeIWant
...
Even then, it seems like getattr() will return an error because attributeIWant() is supposed to be a function call, it's not actually an attribute. I'm not certain that this is even within the capabilities of Python to make this happen.
Thank you in advance for reading and/or responding, if anyone is familiar with a way to do this it would save me a bunch of refactoring or additional code.
edit: Additional Clarification
The class for example is outputData, and inside that class you could have and instance of the class furtherData, which has the attribute dataIWant:
class outputData:
example: furtherData
example = furtherData()
example.dataIWant = someData
...
with the python getattr I can't access both attributes directly in outputData and attributes of example unless I use separate calls, the attribute of example needs two calls to getattr.
Edit2: I have found a solution I think works for this, see below
I was able to figure this out - I just wrote a quick function that splits the attribute string (for example outputObj.subObj.propertyIWant) then proceeds down the resultant array, calling getattr on each subobject until it reaches the end of the array and returns the actual attribute.
Code:
def obtainAttribute(sample, attributeString: str):
baseObj = sample
attrArray = attributeString.split(".")
for string in attrArray:
if(attrArray.index(string) == (len(attrArray) - 1)):
return getattr(baseObj,string)
else:
baseObj = getattr(baseObj,string)
return "failed"
sample is the object and attributeString is, for example object.subObject.attributeYouWant
I am trying to build a class object that can take in a list of lists and check the entries to see if one is empty, and if it does, returns a message.
class EmptyCheck():
def __init__(self, some_list):
self.some_list = some_list
def check_empty(some_list):
for item in some_list:
if '' in item:
print('please fill out survey')
data = [[1],[2],[''],['apples']]
x = EmptyCheck(data)
x.check_empty()
The problem seems to be that the EmptyCheck object is not iterable. But this is where I get a bit confused because I am not trying to iterate over the EmptyCheck object, I am trying to iterate over some_list. So I am hoping someone could help to clarify what is going on and help me to understand this issue a bit deeper. I suspect I will need to add some of the special dunder methods, but maybe I don't?
Your check_empty method checks a new list passed as a function argument, not the list you store as an instance attribute. Change it to:
def check_empty(self):
for item in self.some_list:
As a side note, you should return right after the print statement so that you don't print the same message multiple times in case there are multiple sub-lists with empty strings.
This appears simple, but I can't find a good solution.
It's the old 'pass by reference'/ 'pass by value' / 'pass by object reference' problem. I understand what is happening, but I can't find a good work around.
I am aware of solutions for small problems, but my state is very large and extremely expensive to save/ recalculate. Given these constraints, I can't find a solution.
Here is some simple pseudocode to illustrate what I would like to do (if Python would let me pass by reference):
class A:
def __init__(self,x):
self.g=x
self.changes=[]
def change_something(self,what,new): # I want to pass 'what' by reference
old=what # and then de-reference it here to read the value
self.changes.append([what,old]) # store a reference
what=new # dereference and change the value
def undo_changes():
for c in self.changes:
c[0]=c[1] # dereference and restore old value
Edit: Adding some more pseudocode to show how I would like the use the above
test=A(1) # initialise test.g as 1
print(test.g)
out: 1
test.change_something(test.g,2)
# if my imaginary code above functioned as described in its comments,
# this would change test.g to 2 and store the old value in the list of changes
print(test.g)
out: 2
test.undo_changes()
print(test.g)
out: 1
Obviously the above code doesnt work in python due to being 'pass by object reference'. Also I'd like to be able to undo a single change, not just all of them as in the code above.
The thing is... I can't seem to find a good work around. There are solutions out there like these:
Do/Undo using command pattern in Python
making undo in python
Which involve storing a stack of commands. 'Undo' then involves removing the last command and then re-building the final state by taking the initial state and re-applying everything but the last command. My state is too large for this to be feasible, the issues are:
The state is very large. Saving it entirely is prohibitively expensive.
'Do' operations are costly (making recalculating from a saved state infeasible).
Do operations are also non-deterministic, relying on random input.
Undo operations are very frequent
I have one idea, which is to ensure that EVERYTHING is stored in lists, and writing my code so that everything is stored, read from and written to these lists. Then in the code above I can pass the list name and list index every time I want to read/write a variable.
Essentially this amounts to building my own memory architecture and C-style pointer system within Python!
This works, but seems a little... ridiculous? Surely there is a better way?
Please check if it helps....
class A:
def __init__(self,x):
self.g=x
self.changes={}
self.changes[str(x)] = {'init':x, 'old':x, 'new':x} #or make a key by your choice(immutable)
def change_something(self,what,new): # I want to pass 'what' by reference
self.changes[what]['new'] = new #add changed value to your dict
what=new # dereference and change the value
def undo_changes():
what = self.changes[what]['old'] #retrieve/changed to the old value
self.changes[what]['new'] = self.changes[what]['old'] #change latest new val to old val as you reverted your changes
for each change you can update the change_dictionary. Onlhy thing you have to figure out is "how to create entry for what as a key in self.change dictionary", I just made it str(x), just check the type(what) and how to make it a key in your case.
Okay so I have come up with an answer... but it's ugly! I doubt it's the best solution. It uses exec() which I am told is bad practice and to be avoided if at all possible. EDIT: see below!
Old code using exec():
class A:
def __init__(self,x):
self.old=0
self.g=x
self.h=x*10
self.changes=[]
def change_something(self,what,new):
whatstr='self.'+what
exec('self.old='+whatstr)
self.changes.append([what,self.old])
exec(whatstr+'=new')
def undo_changes(self):
for c in self.changes:
exec('self.'+c[0]+'=c[1]')
def undo_last_change(self):
c = self.changes[-1]
exec('self.'+c[0]+'=c[1]')
self.changes.pop()
Thanks to barny, here's a much nicer version using getattr and setattr:
class A:
def __init__(self,x):
self.g=x
self.h=x*10
self.changes=[]
def change_something(self,what,new):
self.changes.append([what,getattr(self,what)])
setattr(self,what,new)
def undo_changes(self):
for c in self.changes:
setattr(self,c[0],c[1])
def undo_last_change(self):
c = self.changes[-1]
setattr(self,c[0],c[1])
self.changes.pop()
To demonstrate, the input:
print("demonstrate changing one value")
b=A(1)
print('g=',b.g)
b.change_something('g',2)
print('g=',b.g)
b.undo_changes()
print('g=',b.g)
print("\ndemonstrate changing two values and undoing both")
b.change_something('h',3)
b.change_something('g',4)
print('g=', b.g, 'h=',b.h)
b.undo_changes()
print('g=', b.g, 'h=',b.h)
print("\ndemonstrate changing two values and undoing one")
b.change_something('h',30)
b.change_something('g',40)
print('g=', b.g, 'h=',b.h)
b.undo_last_change()
print('g=', b.g, 'h=',b.h)
returns:
demonstrate changing one value
g= 1
g= 2
g= 1
demonstrate changing two values and undoing both
g= 4 h= 3
g= 1 h= 10
demonstrate changing two values and undoing one
g= 40 h= 30
g= 1 h= 30
EDIT 2: Actually... after further testing, my initial version with exec() has some advantages over the second. If the class contains a second class, or list, or whatever, the exec() version has no trouble updating a list within a class within a class, however the second version will fail.
I'm quite green on Python and have been looking around for an answer to my particular question. Though I'm not sure if it's a Python specific question, or if I'm simply getting my OOP / design patterns confused.
I've got three files: main.py, board.py and player.py. Board and player each only hold a class Player and Board, main simply starts the game.
However I'm struggling with validating player positions when they are added to the board. What I want is to instantiate the board and consecutively new player object(s) in main.py, but check the board size in player.py when a new player is added to the board, to ensure the player is not outside of bounds upon creation.
As it is now I'm getting a TypeError (getX() missing 1 required positional argument: 'self') when attempting to access the board's size inside of player.py.
Most likely because the board isn't instantiated in that scope. But if I instantiate it in the scope that will be counted as a new object, won't it? And if I pass the board to the player as a variable that would surely be counted as bad practice, wouldn't it?
So how do I go about accessing the instance variables of one class from another class?
I have no idea if this will help, but I made a post on how to save and load using the Pickle import. In the saving function, it refers back to the Player class I created. It might help you, it might not. Here is the link anyway.
Your question is asking about a concept called "dependency injection." You should take some time to read up on it. It details the ways of making one object available to another object that wants to interact with it. While that's too broad to write up here, here are some of the basics:
You could have all objects you care about be global, or contained in a global container. They can all see each other and interact with each other as necessary. This isn't very object-oriented, and is not the best practice. It's brittle (all the objects are tightly bound together, and it's hard to change or replace one), and it's not a good design for testing. But, it is a valid option, if not a good one.
You could have objects that care about each other be passed to each other. This would be the responsibility of something outside of all of the objects (in your case, basically your main function). You can pass the objects in every method that cares (e.g. board.verify_player_position(player1)). This works well, but you may find yourself passing the same parameter into almost every function. Or you could set the parameter either through a set call (e.g. board.set_player1(player1)), or in the constructor (e.g. board = Board(player1, player2)). Any of these are functionally pretty much the same, it's just a question of what seems to flow best for you. You still have the objects pretty tightly bound. That may be unavoidable. But at least testing is easier. You can make stub classes and pass them in to the appropriate places. (Remember that python works well with duck typing: "If it walks like a duck and quacks like a duck, then it's a duck." You can make testing code that has the same functions as your board and player class, and use that to test your functions.)
A frequent pattern is to have these objects be fairly dumb, and to have a "game_logic" or some other kind of controller. This would be given the instances of the board and the two players, and take care of maintaining all of the rules of the game. Then your main function would basically create the board and players, and simply pass them into your controller instance. If you went in this direction, I'm not sure how much code you would need your players or board to have, so you may not like this style.
There are other patterns that will do this, as well, but these are some of the more basic.
To answer your direct questions: yes, the error you're seeing is because you're trying to invoke the class function, and you need it to be on an object. And yes, instantiating in that case would be bad. But no, passing an instance of one class to another is not a bad thing. There's no use in having objects if they don't interact with something; most objects will need to interact with some other object at some point.
You mentioned that you have code available, but it's a good thing to think out your object interactions a little bit before getting too into the coding. So that's the question for you: do you want player1.check_valid_position(board), or board.check_player(player1), or rules.validate_move(player, some_kind_of_position_variable)`. They're all valid, and they all have the objects inter-relate; it's just a question of which makes the most sense to you to write.
It's hard to know your exact issue without seeing some code, but I hope this is useful!
class Player:
def __init__(self, x, y, player_id):
self.x = x
self.y = y
self.id = player_id
class Board:
def __init__(self, width, height):
self.width = width
self.height = height
self.players = {}
def add_player(self, player):
"""keep track of all the players"""
self._validate_player(player)
# add the player to a dict so we can access them quickly
self.players[player.id] = player
def _validate_player(self, player):
"""whatever validation you need to do here"""
if player.x < 0 or player.x >= self.width:
raise ValueError("The player didn't land on the board! Please check X")
if player.y < 0 or player.y >= self.height:
raise ValueError("The player didn't land on the board! Please check Y")
# whatever other checks you need to do
# player is in a valid location!
def main():
# we can make as few or as many players as we'd like!
p1 = Player(10, 20, 0)
p2 = Player(-1, 10, 1) # invalid player
board = Board(50, 50) # we only need to make one board
board.add_player(p1)
board.add_player(p2) # value error
running = True
while running: # simple game loop
player.take_turn() # maybe prompt user to input something
board.update_players() # update player positions
board.display()
running = board.keep_playing() # check for win state
# whatever code you want to run
if __name__ == "__main__":
main()
Here we create an instance of a Player by assigning an x and y position, and in this case also a player ID which we can use to get that player when we need them. If there's only going to be one player, we could just do something like board.player.
In my example, a ValueError is raised when an invalid Player is provided, you can of course do whatever you'd like in the event that a Player is invalid, also your game could have any number of other cases for a Player being invalid.
I've added some method calls for some methods that might make sense for a board game.
As a side note, in python, you generally don't need to write getters/setters, it's perfectly okay to access Class fields directly.
player.x = 10
if player.y == 11: etc.
and if you have need for validation of some sort that could belong in a getter/setter, you can use the #property decorator.
relative noob here! I'm running 2.7, if that helps.
I'm trying to call a function defined in my main application class in a different function (I think that's called inheritance?) But I keep having problems with the number of args I put into my function!
Here's the function (is it called a method? if not, what's a method) I'm trying to call:
def student_list_updater(self, list):
self.StudentListDisplay.delete(0, END)
for student in list:
self.StudentListDisplay.insert(END, student)
And here's the function I'm calling it in (it's inheriting student_list_updater, right?):
def OnRemoveClick(self, student_list_updater):
self.student_list_updater = student_list_updater
index = self.StudentListDisplay.curselection()
index = int(index[0])
del student_list_temp[index]
self.student_list_updater(student_list_temp)
Thank you for the help in advance!
It's a little difficult to understand your question without more of the code, but hopefully this answer points you in the right direction.
First, to clarify, methods are just functions that can be accessed through an instance of a class, so yes, these are methods, but they're also functions--don't get too hung up on it. Next, I don't think inheritance is necessary here--inheritance will be one class inheriting attributes from another, and I believe all of your methods are only in one class (correct me if I'm mistaken).
Now, as to your code: it's giving you an error that one of your methods takes a number of arguments, and you gave it a different number. Well, to me, it looks like you only need to pass one argument for this whole process: student_list_temp to student_list_updater(). Once again, I can't say for sure that this will solve your problems, based on the lack of code you posted, but this might work:
def student_list_updater(self, studentlist): #change list to studentlist,
self.StudentListDisplay.delete(0, END) #Python already has a list() method
for student in studentlist:
self.StudentListDisplay.insert(END, student)
def OnRemoveClick(self): #Remove student_list_updater from the args, it has no value
#self.student_list_updater = student_list_updater #this doesn't do anything
index = self.StudentListDisplay.curselection() #This part I can't really comment on
index = int(index[0]) #without knowing the contents of the
del student_list_temp[index] #Listbox and student_list_temp,
self.student_list_updater(student_list_temp) #but this should call student_list_updater()
#and update the Listbox if it's working
The last thing I want to point out is how you call OnRemoveClick() will probably change. If you're calling it from a Button, it would look like this:
self.btn = Button(self, text='GO', command=self.OnRemoveClick)
Note that you're not passing any arguments to it.
Hope that helps. You also might want to take a look at https://docs.python.org/2/tutorial/classes.html and https://docs.python.org/2/tutorial/modules.html to clear up any classes and functions questions you might have.