weakref pitfall

Odalrick odalrick at hotmail.com
Sat Oct 20 09:47:58 EDT 2007


I'm trying to write a simple game and decided I need an eventmanager.

<code>
import weakref
from collections import defaultdict

class _EventManager( object ):
    def __init__( self ):
        self._handled_events =
defaultdict( weakref.WeakKeyDictionary )

    def register( self, handler, event_type, filter=None ):
        self._handled_events[event_type][handler] = filter

    def deregister( self, handler, event_type ):
        self._handled_events[event_type].pop( handler, None  )

    def handle_event( self, event ):
        event_type = event.type
        for handler, filter in
self._handled_events[event_type].items():
            if filter == None or filter(event):
                handler( event )

eventmanager = _EventManager()

__all__ = [ eventmanager ]
</code>

Fairly simple, yet there was some strange bug that prevented my game
from exiting.

I think what happened was that when __init__ ends, self goes out of
scope, and by extension so does self.handle_quit, Now there are no
more refeences to self.handle_quit, because weakrefs don't count, and
the event gets automatically dropped from my eventmanager. I thought
that wouldn't happen because handle_quit is part of the class and
instance MainGame.

Am I right in my guess? If so, how should I adress this bug? If not,
what is the bug?

<code>
import pygame
from eventmanager import eventmanager

class MainGame( object ):
    def __init__( self, width=1024, height=768 ):
        #Initialize PyGame
        pygame.init()
        self.width = width
        self.height = height
        self.quit_game = False
        #Create the Screen
        self.screen = pygame.display.set_mode( ( self.width,
self.height ) )
        eventmanager.register( self.handle_quit, pygame.QUIT )
        eventmanager.register( self.handle_quit, pygame.KEYDOWN,
key_filter( pygame.K_ESCAPE ) )

    def mainloop( self ):
        handle_event = eventmanager.handle_event
        self.quit_game = False
        while not self.quit_game:
            for event in pygame.event.get():
                handle_event( event )

    def handle_quit( self, event=None ):
        self.quit_game = True

def key_filter( key ):
    def filter( event ):
        return event.key == key
    return filter

def handle_print_event( event ):
    print str( event )

if __name__ == "__main__":
    game = MainGame()
    game.mainloop()
</code>




More information about the Python-list mailing list