gpt4 book ai didi

python - Python `in` 与 `__contains__` 的功能

转载 作者:IT老高 更新时间:2023-10-28 21:12:43 28 4
gpt4 key购买 nike

前几天我第一次在一个类上实现了 __contains__ 方法,结果出乎我的意料。我怀疑 in 有一些微妙之处操作符我不懂,希望有人能赐教。

在我看来,in 运算符不只是简单地包装对象的 __contains__ 方法,而且它还试图强制输出 __contains__ 为 bool 值。例如,考虑类

class Dummy(object):
def __contains__(self, val):
# Don't perform comparison, just return a list as
# an example.
return [False, False]

in 运算符和对 __contains__ 方法的直接调用返回非常不同的输出:

>>> dum = Dummy()
>>> 7 in dum
True
>>> dum.__contains__(7)
[False, False]

再次,看起来 in 正在调用 __contains__ 但随后将结果强制转换为 bool。除了 __contains__ documentation 之外,我在任何地方都找不到这种行为的记录。说 __contains__ 应该只返回 TrueFalse

我很高兴遵守约定,但有人能告诉我 in__contains__ 之间的确切关系吗?

结语

我决定选择@eli-korvigo 回答,但大家应该看看@ashwini-chaudhary comment关于bug ,下面。

最佳答案

使用来源,卢克!

让我们追溯一下 in 操作符的实现

>>> import dis
>>> class test(object):
... def __contains__(self, other):
... return True

>>> def in_():
... return 1 in test()

>>> dis.dis(in_)
2 0 LOAD_CONST 1 (1)
3 LOAD_GLOBAL 0 (test)
6 CALL_FUNCTION 0 (0 positional, 0 keyword pair)
9 COMPARE_OP 6 (in)
12 RETURN_VALUE

如你所见,in 操作符变成了COMPARE_OP 虚拟机指令。您可以在 ceval.c 中找到

TARGET(COMPARE_OP)
w = POP();
v = TOP();
x = cmp_outcome(oparg, v, w);
Py_DECREF(v);
Py_DECREF(w);
SET_TOP(x);
if (x == NULL) break;
PREDICT(POP_JUMP_IF_FALSE);
PREDICT(POP_JUMP_IF_TRUE);
DISPATCH();

看看 cmp_outcome()

中的开关之一
case PyCmp_IN:
res = PySequence_Contains(w, v);
if (res < 0)
return NULL;
break;

这里我们有 PySequence_Contains 调用

int
PySequence_Contains(PyObject *seq, PyObject *ob)
{
Py_ssize_t result;
PySequenceMethods *sqm = seq->ob_type->tp_as_sequence;
if (sqm != NULL && sqm->sq_contains != NULL)
return (*sqm->sq_contains)(seq, ob);
result = _PySequence_IterSearch(seq, ob, PY_ITERSEARCH_CONTAINS);
return Py_SAFE_DOWNCAST(result, Py_ssize_t, int);
}

这总是返回一个 int(一个 bool 值)。

附言

感谢 Martijn Pieters 提供 way找到 in 操作符的实现。

关于python - Python `in` 与 `__contains__` 的功能,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38542543/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com