起步

文档中 https://docs.python.org/3.8/r... 示意对于 x is y 当且仅当两个变量指向同一对象时才为真。对象能够通过 id() 函数来查看它的身份(id() 函数返回了对象在内存中的映射)。

is 与 is not 的字节码

isis not 都是操作符。 is not 是整体的,千万别把 x is not y 当做是 x is (not y)

来看看这两个操作符对应的字节码(基于 Python 3.8):

>>> def fun():...   x is y...   x is not y... >>> import dis>>> dis.dis(fun)  2           0 LOAD_GLOBAL              0 (x)              2 LOAD_GLOBAL              1 (y)              4 COMPARE_OP               8 (is)              6 POP_TOP  3           8 LOAD_GLOBAL              0 (x)             10 LOAD_GLOBAL              1 (y)             12 COMPARE_OP               9 (is not)             14 POP_TOP             16 LOAD_CONST               0 (None)             18 RETURN_VALUE>>>

对于 COMPARE_OP 对应的动作

case TARGET(COMPARE_OP): {    PyObject *right = POP();    PyObject *left = TOP();    PyObject *res = cmp_outcome(tstate, oparg, left, right);    Py_DECREF(left);    Py_DECREF(right);    SET_TOP(res);    if (res == NULL)        goto error;    PREDICT(POP_JUMP_IF_FALSE);    PREDICT(POP_JUMP_IF_TRUE);    DISPATCH();}

这部分的代码的含意是先将代比照的两个操作数从栈中取出,通过 cmp_outcome(tstate, oparg, left, right) 失去两数的操作后果,再将后果 res 放入栈顶。

cmp_outcome 函数的相干代码是:

static PyObject *cmp_outcome(PyThreadState *tstate, int op, PyObject *v, PyObject *w){    int res = 0;    switch (op) {    case PyCmp_IS:        res = (v == w);        break;    case PyCmp_IS_NOT:        res = (v != w);        break;        ...    }    v = res ? Py_True : Py_False;    Py_INCREF(v);    return v;}

cmp_outcome() 函数中,仅通过比照两个指针的值是否相等来判断它们是否是指向同一对象。

纯Python代码解释

通过 id() 函数能够来判断某一对象在内存中对应的地址,因而用它也能够来判断两个变量是否指向了同一对象:

def _is(a, b):    return id(a) == id(b)def _is_not(a, b):    return id(a) != id(b)