Can I write a function that detect if it is called from 'with'-statement or not?
-
11-10-2019 - |
Question
More specifically, can I detect if a function is called as EXPR
in with EXPR: BLOCK
statement?
I am trying to make myself familiar with the usage of with
-statement in python. As a first step, I re-implemented an example, which generate marked up text, appeared in the reference of contextlib.contextmanager
(ignoring exception handling for now).
class Markup(object):
def __init__(self):
self.tags = []
self.append = self.tags.append
self.pop = self.tags.pop
def tag(self, name):
self.append(name)
return self
def __enter__(self):
print('<{}>'.format(self.tags[-1]))
def __exit__(self, exc_type, exc_value, traceback):
print('</{}>'.format(self.pop()))
>>> m = Markup()
>>> with m.tag('ELEMENT'):
... print('sample text')
...
<ELEMENT>
sample text
</ELEMENT>
This works as expected. Then, I got to think if tag()
can also generate empty elements:
>>> m = Markup()
# if a function appears as EXPR of "with EXPR: BLOCK", 'ELEMENT' is a container element. .
>>> with m.tag('ELEMENT'):
... print('sample text')
...
<ELEMENT>
sample text
</ELEMENT>
# in other cases, ELEMENT is an empty element.
>>> m.tag('ELEMENT')
<ELEMENT/>
To my naive eyes, it seems doable if callee can detect if it is called from with
-statement or not. However, I do not know if this detection is possible or not. Is there such a way and, if there is, how?
Solution
You're not actually calling tag()
"from" the with
statement. You're calling tag()
, then passing the return value from tag()
to the with
statement, which then calls __enter__
on that passed-in value, then runs the body, then calls __exit__
.
So no, you can't detect the with
statement before it's actually invoked (which is after tag()
is called).