Skip Montanaro skip at
Wed Nov 14 09:33:47 CET 2001

    Ciobanu> class DataBase:
    Ciobanu>    def __init__( self):
    Ciobanu>       self.__dictionary = {}
    Ciobanu>    def __getitem__( self, key):
    Ciobanu>       return self.__dictionary[key]
    Ciobanu>    def __setitem__( self, key, value):
    Ciobanu>       self.__dictionary[key] = value

    Ciobanu> Now, consider that this DataBase class is to be used in a real
    Ciobanu> world program, specifically in a threaded world. This would
    Ciobanu> imply I use locks, which brings me to the actual
    Ciobanu> question. Unfortunately the Python Library Reference isn't
    Ciobanu> clear enough ( to me, at least) about this particular detail:

    Ciobanu>    Is it safe to call __getitem__ without placing locks ?

No.  Presuming a value associated with key exists, you will get a consistent
value (not a garbage half-old/half-new value), but it might be an old one
(__setitem__ could sneak in and change it on you).  The code for your
__getitem__ method compiles into several bytecode instructions:

          0 LOAD_FAST                0 (self)
          3 LOAD_ATTR                1 (__dictionary)
          6 LOAD_FAST                1 (key)
          9 BINARY_SUBSCR       
         10 RETURN_VALUE        

The global interpreter lock can be released after any of them, allowing
another thread to run, and possibly change things behind your back.

More importantly, you might lose the key altogether.  Suppose your code
looks like this:

    db = Database()
    ... fill it up with interesting stuff ...
    for key in db.keys():
        print db[key]

You have to secure a lock before the for loop begins and only release it
after the loop terminates to guarantee that the list of keys you got at the
start is still valid while the loop body executes.

So, it's worse than you thought.  Not only must you lock __getitem__, you
have to lock at a higher level than that.

Skip Montanaro (skip at

More information about the Python-list mailing list