<p>不幸的是,正如评论中所讨论的,这并非在所有情况下都可能。创建上下文管理器时,<a href="http://hg.python.org/cpython/file/75c0b65591fd/Python/ceval.c#l2541" rel="noreferrer">following code is run</a>(至少在cpython2.7中是这样的)。我无法评论其他实现):</p>
<pre><code> case SETUP_WITH:
{
static PyObject *exit, *enter;
w = TOP();
x = special_lookup(w, "__exit__", &exit);
if (!x)
break;
SET_TOP(x);
/* more code follows... */
}
</code></pre>
<p>使用<code>__exit__</code>宏将<code>SET_TOP</code>方法推送到堆栈上,该宏是<a href="http://hg.python.org/cpython/file/75c0b65591fd/Python/ceval.c#l826" rel="noreferrer">defined as</a>:</p>
^{pr2}$
<p>堆栈指针依次设置在<a href="http://hg.python.org/cpython/file/75c0b65591fd/Python/ceval.c#l937" rel="noreferrer">frame eval</a>开头的帧值堆栈的顶部:</p>
<pre><code>stack_pointer = f->f_stacktop;
</code></pre>
<p>其中f是在<a href="http://hg.python.org/cpython/file/75c0b65591fd/Include/frameobject.h" rel="noreferrer">frameobject.h</a>中定义的帧对象。对我们来说不幸的是,这是线索停止的地方。python可访问框架对象是用<a href="http://hg.python.org/cpython/file/75c0b65591fd/Objects/frameobject.c#l17" rel="noreferrer">following methods only</a>定义的:</p>
<pre><code>static PyMemberDef frame_memberlist[] = {
{"f_back", T_OBJECT, OFF(f_back), RO},
{"f_code", T_OBJECT, OFF(f_code), RO},
{"f_builtins", T_OBJECT, OFF(f_builtins),RO},
{"f_globals", T_OBJECT, OFF(f_globals), RO},
{"f_lasti", T_INT, OFF(f_lasti), RO},
{NULL} /* Sentinel */
};
</code></pre>
<p>不幸的是,它没有包括我们需要的<code>f_valuestack</code>。这是有意义的,因为<code>f_valuestack</code>是<code>PyObject **</code>类型,它需要包装在一个对象中,以便从python以任何方式访问。在</p>
<p>TL;DR:我们要寻找的<code>__exit__</code>方法只位于一个地方,即frame对象的值堆栈,而cPython不允许python代码访问值堆栈。在</p>