Is it possible to access enclosing context manager?

后端 未结 3 1662
灰色年华
灰色年华 2020-12-16 12:01

There are essentially three ways to use the with statement:

Use an existing context manager:

with manager:
    pass

Create a contex

3条回答
  •  北荒
    北荒 (楼主)
    2020-12-16 12:55

    Unfortunately, as discussed in the comments, this is not possible in all cases. When a context manager is created, the following code is run (in cPython 2.7, at least. I can't comment on other implementations):

        case SETUP_WITH:
        {
            static PyObject *exit, *enter;
            w = TOP();
            x = special_lookup(w, "__exit__", &exit);
            if (!x)
                break;
            SET_TOP(x);
            /* more code follows... */
        }
    

    The __exit__ method is pushed onto a stack with the SET_TOP macro, which is defined as:

    #define SET_TOP(v)        (stack_pointer[-1] = (v))
    

    The stack pointer, in turn, is set to the top of the frame's value stack at the start of frame eval:

    stack_pointer = f->f_stacktop;
    

    Where f is a frame object defined in frameobject.h. Unfortunately for us, this is where the trail stops. The python accessible frame object is defined with the following methods only:

    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 */
    };
    

    Which, unfortunaltey, does not include the f_valuestack that we would need. This makes sense, since f_valuestack is of the type PyObject **, which would need to be wrapped in an object to be accessible from python any way.

    TL;DR: The __exit__ method we're looking for is only located in one place, the value stack of a frame object, and cPython doesn't make the value stack accessible to python code.

提交回复
热议问题