On Tue, Nov 3, 2015 at 6:22 PM, Steven D'Aprano <st...@pearwood.info> wrote: > A lot can happen in the few microseconds between > checking for the existence of the file and actually opening it -- the file > could be renamed or deleted.
And a lot of microseconds can happen between two opcodes, too. Even inside a Python script, it's possible for threads or other arbitrary code execution to get in your way: if "foo" in counters: # context switch here! process(counters["foo"]) Garbage collection can happen at any time. Here's an (admittedly arbitrary) example of how the above could be broken: >>> class X: ... def __init__(self, name, dict): ... self.dict = dict; self.name = name ... self.dict[self.name] = 0 ... def frob(self): ... self.dict[self.name] += 1 ... def __del__(self): ... del self.dict[self.name] ... >>> counters = {} >>> x = X("foo", counters) >>> x.refcycle = x >>> counters {'foo': 0} >>> del x >>> counters {'foo': 0} >>> gc.collect() 10 >>> counters {} If the cycle-detecting garbage collector happens to be called immediately after the 'if', you'll get an exception. So I suppose what you might do is this: try: # Optimization: Since a lot of these names won't be # in the dict, we check first rather than relying on the # exception. Since counters get removed in the __del__ # method, we can't depend 100% on the 'in' check, # but an unnecessary try block is cheap. if "foo" in counters: process(counters["foo"]) except KeyError: pass But any time you need a block comment to justify your code, you'd better be REALLY sure the performance benefit is worth the complexity. For reliability, expect exceptions. ChrisA -- https://mail.python.org/mailman/listinfo/python-list