Developer Tips
by Zhihao Yuan
Let’s say we have a context manager that accepts two arguments:
@contextmanager
def colored(idx, color):
push_style_color(idx, *color)
yield
pop_style_color()
How do we write a context manager that “freezes” the first argument?
with colored_text(pink): # idx=COLOR_TEXT
...
One way is to bind the first argument:
def colored_text(color):
return color(COLOR_TEXT, color)
But this function no longer looks like a context manager.
Because the wrapped function of a context manager is a generator, it’s possible to chain context managers in the way we chain generators:
@contextmanager
def colored_text(color):
yield from color.__wrapped__(COLOR_TEXT, color)
This extra thought process gives us additional capability. Since we are writing a context manager again, we can extend it as a context manager:
@contextmanager
def color_replaced_if(cond, idx, color):
if cond:
yield from colored.__wrapped__(idx, color)
else:
yield