I'm using shelve to store some data.
Traceback (most recent call last):
File "rogue.py", line 312, in <module>
curses.wrapper(game)
File "/usr/lib/python3.3/curses/__init__.py", line 94, in wrapper
return func(stdscr, *args, **kwds)
File "rogue.py", line 289, in game
save_game(y,x)
File "rogue.py", line 119, in save_game
file['player'] = player
File "/usr/lib/python3.3/shelve.py", line 124, in __setitem__
p.dump(value)
_pickle.PicklingError: Can't pickle <class 'method'>: attribute lookup builtins.method failed
I looked around and found stuff about unbound methods could be causing this, but I can't find the problem in my code.
The problem arises at
file['player'] = player
player is class entity:
player = entity(y,x, '@', 200, False)
This is the code for class entity:
class entity:
def __init__(self, y, x, ch, speed, ai=True):
self.y = y
self.x = x
self.ch = ch
self.speed = speed
self.ai = ai
self.ap = 0
self.current_action = {'action': self.wait, 'cost': self.speed}
self.my_turn = False
def draw(self):
world[self.y][self.x].walkable = False
gamepad.addch(self.y, self.x, self.ch)
def take_turn(self):
self.my_turn = True
cost = self.current_action['cost']
self.current_action['action']()
return cost
def move(self, dy, dx):
if self.my_turn == False:
self.current_action = {'action': partial(self.move, dy,dx), 'cost':200}
deck.append(self)
if self.my_turn == True:
#p = previous
py = self.y
px = self.x
pt = world[py][px]
#Paint previous ground tile
pt.walkable = True
gamepad.addch(pt.y,pt.x,pt.ch)
if world[dy][dx].walkable == True:
self.y = dy
self.x = dx
world[dy][dx].walkable = False
if self.ai == False:
draw_map(self.y,self.x)
self.my_turn = False
return self.y,self.x
def wait(self):
self.current_action = {'action': self.wait, 'cost': self.speed}
def drunk_move(self):
dy = self.y + random.randint(-1,1)
dx = self.x + random.randint(-1,1)
self.move(dy, dx)
def ai_simple(self):
#Figure out if player is higher or not:
wherey = self.y - player.y
if wherey > 0:
dy = self.y-1
else:
dy = self.y+1
wherex = self.x - player.x
if wherex > 0:
dx = self.x-1
else:
dx = self.x+1
self.move(dy, dx)
Before posting this I tried to take one final look with pudb - and I'm also getting an error on
file['world'] = world
_
│ File "/usr/lib/python3.3/shelve.py", line 124, in │
│__setitem__ │
│ p.dump(value) │
│_pickle.PicklingError: Can't pickle <class │
│'__main__.tile'>: attribute lookup __main__.tile failed │
(which does not show when running the code without pudb)
This is world:
world = [[ tile(yy,xx,True,'.')
for xx in range(WORLD_WIDTH) ]
for yy in range(WORLD_HEIGHT) ]
this is class tile:
class tile:
def __init__(self,y,x,walkable,ch):
self.x = x
self.y = y
self.walkable = walkable
self.ch = ch
Finally, this is the complete function that calls shelve:
def save_game():
file = shelve.open('savegame', 'n')
file['world'] = world
file['player']= player
file.close()
I believe that's all the relevant code.
What's causing these Errors?
The first problem is caused by this line in your entity class:
self.current_action = {'action': self.wait, 'cost': self.speed}
current_action
contains references to bound methods, which can't be pickled. You could use __getstate__
and __setstate__
do change your pickling behaviour, so you don't pickle the method but it's name (or name and arguments in the case where have assigned a partial
object) when pickling, and restore that values at unpickling time.
I'm not really sure about your second problem, but if it only happens when you run it inside a debugger, it's probably an issue with how the debuger loads the __main__
module. You could try to move your __main__
block into another module and import and lounch your code from there. Sometimes that can fix problems like these.