How to use pickle to save all objects in a program? - python

I have been looking everywhere for information on pickle, and I thought I had had figured it out, but I am having a bit of a problem getting it to work properly.
So I use python 3.3.1. I have a pygame game with many rooms (around 200), each room is its own child instance of a parent class, many with their own variables to keep track of all sorts of things that happen in their room. As the player goes from room to room, I of course want the changes the player does to each room to be saved when the player saves a game. I have sort of a double question.
So here is more or less what I do:
import pickle
with gzip.GzipFile("Saved Games/"+file_name, 'wb') as output:
pickle.dump(room001, output, pickle.HIGHEST_PROTOCOL)
...
pickle.dump(room200, output, pickle.HIGHEST_PROTOCOL)
pickle.dump(player, output, pickle.HIGHEST_PROTOCOL)
So I guess that saves. But when I load it later, using:
with gzip.GzipFile("Saved Games/"+file_name, 'r') as loadfile:
room001 = pickle.load(loadfile)
...
room200 = pickle.load(loadfile)
player = pickle.load(loadfile)
at first everything seems okay. It seems to load with no problems, but then I notice the game is acting a little strangely. it is as if it is not using the data it loaded from the pickle.
For example, one room might have some bees flying about. I enter the room and see the bees as normal, but when the event function for the room tries to make the bees move about, they don't.
It would look something like this:
def room001_events():
room001.bee_pos_x += room001.bee_speed
if room001.bee_pos_x < 0 or room001.bee_pos_x > 600:
room001.bee_speed *= -1
Prior to the load the bees would happily bounce back and forth, but after it, they wouldnt move at all. So I am wondering what I am doing wrong with the load process. the function is being accessed and when I print out the values, they seem to be changing, but the bees on the screen don't move.
Also, I am wondering if there is some way to iterate over all the rooms in the program without having to list them individually. I have tried using shelve as per this question, but it just crashes on load (it mostly seems to have problems with surfaces from what I can tell because it keeps giving me pygame.error: display Surface quit even though I never called pygame.quit() at all).

Your problem isn't pickle. Your problem is the assumption that restoring the state of a room from a pickle is sufficient to have it operate normally when you load the pickle. I'd be willing to bet you have no tests to validate that assumption.
When you save (pickle) an instance, the values of its instance variables are saved as part of the pickle. When you reload them their __init__() methods will not normally be called, which is presumably how actions are started. So are you sure that there's enough state information in the pickle for things to just resume where they left off?
The easiest way to save all the rooms without having to list them individually is to have a list containing the rooms. Then your code would refer to (say) rooms[100] rather than room100, and you can just pickle the rooms[] list to save them all with a single statement.

Related

How do I properly save state in case of an exception in python?

I want to
load data from files,
work on that data,
and eventually save that data back to files.
However, since step 2 may take several hours I want to make sure that progress is saved in case of an unexpected exception.
The data is loaded into an object to make it easy to work with it.
First thing that came to my mind was to turn that objects class into a context manager and use the with-statement. However I'd have to write practically my entire program within that with-statement and that doesn't feel right.
So I had a look around and found this question which essentially asks for the same thing. Among the answers this one suggesting weakref.finalize seemed the most promising to me. However, there is a note at the bottom of the documentation that says:
Note: It is important to ensure that func, args and kwargs do not own any references to obj, either directly or indirectly, since otherwise obj will never be garbage collected. In particular, func should not be a bound method of obj.
Since I'd want to save fields of that object, I'd reference them, running right into this problem.
Does this mean that the objects __exit__-function will never be called or that it will not be called until the program crashes/exits?
What is the pythonic way of doing this?
It's a little hacky, and you still wrap your code, but I normally just wrap main() in a try except block.
Then you can handle except with a pdb.set_trace(), which means whatever exception you get, your program will drop into an interactive terminal instead of breaking.
After that, you can manually inspect the error and dump any processed data into a pickle or whatever you want to do. Once you fix the bug, setup your code to read the pickle and pick up from where it left off.

Saving Text Based Adventure Game

I'm looking for an efficient way to save my game coded in python. I've looked at pickle, but I'm not sure it will suit my needs as there is a lot of info that needs to be saved.
The way I understand pickle is it will take whatever I give it and dump it into a file, which sounds great. But not only do I have the player character to save, theres the rooms that the character has already been, the state of the rooms, if the user opened up treasure chests, etc. And if I understand pickle correctly, I would have to input each room manually for that to work.
Is there a better way to do this? Would I be better off creating a database of some kind? Or am I just not using pickle correctly?
Perhaps I'm missing something, but why not put all of the data you mention into a dictionary. It may even be a multi-level dictionary. Something like:
{
"player_info":{"name":"Bart", ..},
"current_state_of_game":{"cur_location":"library", "prior_room":"kitchen", ..}
}
Then pickle that?

How to structure game instance data in Python

I am implementing a game server in python. The GameServer class holds multiple game instances, which each hold multiple players. I am trying to figure out the most optimal data structures to use. There is a single function that receives all incoming data, and it needs to find the player within the games, and update the info.
Currently, GameServer has a set of GameInstances, and GameInstance has a set of players. This requires me to iterate through every game and player to find the correct game, and I don't think this is the best way to do it, because it will have to be run hundreds of times per second.
The incoming data has a connection (from which the data was received), and the message. This means I store a connection for every player within their class, so that I can send messages back to a specific player. I can't keep a dict of every player connection, because they have to be grouped by game instance. Please help me understand the most efficient way to structure this.
Currently, GameServer has a set of GameInstances, and GameInstance has a set of players. This requires me to iterate through every game and player to find the correct game, and I don't think this is the best way to do it, because it will have to be run hundreds of times per second.
You're right! And while I will answer your specific question, what you should do is read about datastructures. It's essential that every working programmer have at least a basic understanding of the most common datastructures, and their performance characteristics.
Based on your description of your problem, you need to maintain a mapping, probably using a hashtable, between a key which identifies each game, and the object which describes it.

How to add a track to an iTunes playlist using Python and Scripting Bridge

I learned how to create a playlist in a previous question, but now I can't figure out how to add tracks to it. Right now I have:
tracks.sort(key=lambda tup: tup[0])
i = 0
for trackList in generatePlaylists(tracks,10):
i += 1
playlistname = str(i)
p = {'name': playlistname}
playlist = iTunes.classForScriptingClass_("playlist").alloc().initWithProperties_(p)
iTunes.sources()[0].playlists().insertObject_atIndex_(playlist, 0)
# Find the playlist I just made
for playlist in iTunes.sources()[0].playlists():
if playlist.name() == playlistname:
newPlaylist = playlist
# Add the tracks to it
for track in trackList:
print track[1].name()
iTunes.add_to_(track[1],newPlaylist)
My tracks are in a list of tuples tracks, where the first element of the tuple is a score and the second is the actual track object. generatePlaylists is an iterator which splits all library tracks into 10 lists.
The above code runs without error, but in iTunes the playlists are empty.
First, here's the short answer:
track.duplicateTo_(newPlaylist)
The problem is that iTunes.add_to_ sends the add command, which takes a file (alias) and imports it into a playlist; you want to send the duplicate command, which takes any object and makes another copy of the object. You don't have a file, you have a track. (You could get a file via track.location(), but you don't want to re-import the file, just copy the track over.)
Also, in this case, you need to call the method on the track, rather than calling it on the app and passing it the track.
The first half of this is hard to explain without a solid understanding of the iTunes object model (and the AE model underneath it). But you don't really need to understand it. In most cases, by looking over the iTunes scripting dictionary (in AppleScript Editor) and trial and error (in AppleScript Editor or with py-appscript) you can figure it out what you want. (Just make sure you're working on a scrap library, or have a backup…) In this case, the only commands it could possibly be are add, copy, duplicate, or move, so just try them all and see what they do. Or, alternatively, go to dougscripts and download a bunch of samples and find one that does what you want.
The second half of this, figuring out how to translate to ScriptingBridge… well, I can't explain it without going into a long rant on SB (which hhas does much better than me, if you want to read one). But the basics are this: As far as iTunes is concerned, duplicate is a command. If you give it a direct object (tell application "iTunes" to duplicate theTrack to thePlaylist) it'll use that; if not, you're asking the subject to duplicate itself (tell theTrack to duplicate to thePlaylist). It works exactly like English. But SB insists on an object-oriented model, where duplicate is a method on some object. So, only one of those two forms is going to work. In general, you can figure out which by just looking at dir(iTunes) and dir(track) to see which one has a method that looks like the command you want.
As you can tell from the above, you've got a lot of trial and error ahead of you if you're trying to do anything complicated. Good luck, and keep asking.
PS, I have no idea why your code fails silently. The obvious way the add_to_ method should translate into a command should raise a -1708 error (as appscript iTunes.add(track, to=newPlaylist) or AppleScript add theTrack to newPlaylist both do…).

What are cycles ? in relation to python

im using the fantastic eric4 ide to code python, it's got a tool built in called 'cyclops', which is apparently looking for cycles. After running it, it gives me a bunch of big bold red letters declaring there to be a multitude of cycles in my code. The problem is the output is nearly indecipherable, there's no way im gonna understand what a cycle is by reading its output. ive browsed the web for hours and cant seem to find so much as a blog post. when the cycles pile up to a certain point the profiler and debugger stop working :(.
my question is what are cycles, how do i know when im making a cycle, how do i avoid making cycles in python. thanks.
A cycle (or "references loop") is two or more objects referring to each other, e.g.:
alist = []
anoth = [alist]
alist.append(anoth)
or
class Child(object): pass
class Parent(object): pass
c = Child()
p = Parent()
c.parent = p
p.child = c
Of course, these are extremely simple examples with cycles of just two items; real-life examples are often longer and harder to spot. There's no magic bullet telling you that you just made a cycle -- you just need to watch for it. The gc module (whose specific job is to garbage-collect unreachable cycles) can help you diagnose existing cycles (when you set the appropriate debug flags). The weakref module can help you to avoid building cycles when you do need (e.g.) a child and parent to know about each other without creating a reference cycle (make just one of the two mutual references into a weak ref or proxy, or use the handy weak-dictionary containers that the module supplies).
All Cyclops tells you is whether there are objects in your code that refer to themselves through a chain of other objects. This used to be an issue in python, because the garbage collector wouldn't handle these kinds of objects correctly. That problem has since been, for the most part, fixed.
Bottom line: if you're not observing a memory leak, you don't need to worry about the output of Cyclops in most instances.

Categories