Advertisement
Guest User

Generators, Context Manager and Decorators in Python

a guest
Oct 21st, 2011
488
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 3.45 KB | None | 0 0
  1. def pause():
  2.     raw_input('\nPress enter to continue\n')
  3.  
  4.  
  5. def process(content):
  6.     pass
  7.     # Expensive init
  8.  
  9.     # Work
  10.  
  11.     # Cleanup
  12.  
  13.  
  14. contents = [object()] * 5
  15.  
  16.  
  17.  
  18.  
  19.  
  20.  
  21.  
  22.  
  23.  
  24.  
  25.  
  26.  
  27.  
  28.  
  29.  
  30. def simple_example():
  31.     # Init ...
  32.     print '1> Init generator'
  33.  
  34.     content = yield
  35.     print '1> First content received'
  36.     while content is not None:
  37.         # Work ...
  38.         print '1> Work on content'
  39.         result = process(content)
  40.         content = yield result
  41.  
  42.     # Cleanup ...
  43.     print '1> Cleanup generator'
  44.  
  45. # How to use it ?
  46.  
  47. print 'M> Creating an instance of the generator'
  48. processor = simple_example()
  49. print 'M> Done'
  50. print 'M> Booting generator'
  51. processor.send(None)            # Always have to send None to bootstrap
  52. print 'M> Done'
  53. for content in contents:
  54.     result = processor.send(content)
  55.  
  56. try:
  57.     print 'M> Send end of stream marker'
  58.     processor.send(None)            # Send None to finish. Raises StopIteration
  59. except StopIteration:
  60.     print 'M> Done'
  61. else:
  62.     print 'M> Failed'
  63.  
  64.  
  65.  
  66.  
  67. pause()
  68.  
  69.  
  70.  
  71. # Verbose, let's use a content manager to do send(None)
  72.  
  73. class CoMethod(object):
  74.  
  75.     def __init__(self, iterator):
  76.         self._iterator = iterator
  77.  
  78.     def __enter__(self):
  79.         print '-> Enter context manager'
  80.         self._iterator.send(None)
  81.         return self             # Could return self.__iterator here
  82.  
  83.     def __exit__(self, exc_type, exc_val, exc_tb):
  84.         print '-> Exit context manager'
  85.         if exc_type is None:
  86.             try:
  87.                 self._iterator.send(None)
  88.             except StopIteration:
  89.                 pass
  90.  
  91.     def __call__(self, value):
  92.         return self._iterator.send(value)
  93.  
  94.     def __iter__(self):
  95.         # Iterator protocol
  96.         return self._iterator
  97.  
  98.  
  99. # Now we can use it like this:
  100.  
  101. with CoMethod(simple_example()) as processor:
  102.     for content in contents:
  103.         processor(content)
  104.  
  105.  
  106.  
  107.  
  108. pause()
  109.  
  110.  
  111.  
  112.  
  113. # Prettier ?
  114. # Let's make a decorator
  115.  
  116. import functools
  117.  
  118. def comethod(func):
  119.  
  120.     @functools.wraps(func)
  121.     def wrapped(*args, **kwargs):
  122.         return CoMethod(func(*args, **kwargs))
  123.  
  124.     return wrapped
  125.  
  126. # Definition
  127.  
  128. @comethod
  129. def second_example():
  130.     # Init ...
  131.     print '2> Init generator'
  132.  
  133.     content = yield
  134.     while content is not None:
  135.         # Work ...
  136.         print '2> Work generator'
  137.         result = process(content)
  138.         content = yield result
  139.  
  140.     # Cleanup ...
  141.     print '2> Clean generator'
  142.  
  143. # Now we can use it like this:
  144.  
  145. with second_example() as processor:
  146.     for content in contents:
  147.         processor(content)
  148.  
  149.  
  150.  
  151. pause()
  152.  
  153.  
  154.  
  155. # Nested
  156.  
  157. @comethod
  158. def counter_example(parent, **options):
  159.     # Init
  160.     print '3> Init counter'
  161.     count = 0
  162.  
  163.     content = yield
  164.     while content is not None:
  165.         result = parent(content)
  166.         # Work
  167.         print '3> Count'
  168.         count += 1
  169.         content = yield result
  170.  
  171.     # Cleanup
  172.     print '3> Cleanup, saw', count, 'elements'
  173.  
  174.  
  175. # How to use it
  176.  
  177. with second_example() as processor:
  178.     with counter_example(processor) as counter:
  179.         for content in contents:
  180.             counter(content)
  181.  
  182.  
  183.  
  184.  
  185.  
  186. pause()
  187.  
  188.  
  189.  
  190.  
  191.  
  192.  
  193.  
  194.  
  195. # Last helper, a map function on a CoMethod
  196.  
  197. CoMethod.map = lambda self, iterable: map(self._iterator.send, iterable)
  198.  
  199.  
  200.  
  201. # How to use it
  202.  
  203. with second_example() as processor:
  204.     with counter_example(processor) as counter:
  205.         counter.map(contents)
  206.  
  207.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement