If you're using Python 3.4+, select.epoll already supports context — you're clear to just write with epoll() as E: … and everything will be OK. The epoll descriptor will get properly closed, detached, etc.

But if you're operating on legacy 2 or ≤3.3 systems, writing bilingual code, etc., you might need to write a shim.

Thankfully, this is straightforward:

import select
if hasattr(select.epoll, '__enter__'):
epoll_with = select.epoll
else:
class epoll_with:
'''contextlib wrapper for python2's epoll'''
def __init__(self, *args, **kwargs):
self._E = select.epoll(*args, **kwargs)
def __enter__(self):
return self._E
def __exit__(self, exc_type, exc_value, traceback):
self._E.close()

with epoll_with() as E:
E.register(fd, flags)
…

Note that this isn't a true "polyfill" yet: the same class can't be used both directly and as a contextmanager (at least not in Python 2/≤3.3). I'll update this post with a proper polyfill at some point, but doing is non-trivial because “TypeError: type 'select.epoll' is not an acceptable base type”.

Warning: This site uses Akismet to filter spam. Until or unless I can find a suitable replacement anti-spam solution, this means that (per their indemnification document) all commenters' IP addresses will be sent to Automattic, Inc., who may choose to share such with 3rd parties.
If this is unacceptable to you, I highly recommend using an anonymous proxy or public Wi-Fi connection when commenting.