Skip to content

Instantly share code, notes, and snippets.

@moreati
Created July 30, 2022 09:01
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save moreati/4448f2b5e7dc7a712bdcb8426b258752 to your computer and use it in GitHub Desktop.
Save moreati/4448f2b5e7dc7a712bdcb8426b258752 to your computer and use it in GitHub Desktop.
Combined Python context manager, iterator, and iterable; with a generator-like send() method
EVENS = object()
STOP = object()
class CM():
def __init__(self, n=10):
print('__init__() called')
self.n = n
self._it = iter(range(n))
self._evens = False
self._stop = False
@staticmethod
def is_odd(n):
return n % 2
# Context Manager protocol
def __enter__(self):
print('__enter__() called')
return self
# exc_* are None on the happy path, otherwise Return True to suppress
def __exit__(self, exc_type, exc_value, exc_traceback):
print('__exit__() called')
# Iterable protocol
def __iter__(self):
print('__iter__() called')
return self
# Iterator protocol
def __next__(self):
if self._stop:
raise StopIteration
v = next(self._it)
if self._evens and self.is_odd(v):
v = next(self._it)
return v
def send(self, value):
if value is EVENS:
self._evens = value
if value is STOP:
self._stop = value
if __name__ == '__main__':
with CM() as cm:
for i in cm:
print(i)
if i == 1:
cm.send(EVENS)
if i >= 6:
cm.send(STOP)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment