假设我定义了以下变量:
mode = "access"
allowed_modes = ["access", "read", "write"]
Run Code Online (Sandbox Code Playgroud)
我目前有一个类型检查语句
assert any(mode == allowed_mode for allowed_mode in allowed_modes)
Run Code Online (Sandbox Code Playgroud)
但是,似乎我可以简单地替换它
assert mode in allowed_modes
Run Code Online (Sandbox Code Playgroud)
根据ThiefMaster在Python List Class __contains__ Method Functionality中的回答,这两个应该是等价的.确实如此吗?我怎样才能通过查找Python的源代码轻松验证这一点?
不,他们不相同.例如:
>>> mode = float('nan')
>>> allowed_modes = [mode]
>>> any(mode == allowed_mode for allowed_mode in allowed_modes)
False
>>> mode in allowed_modes
True
Run Code Online (Sandbox Code Playgroud)
有关详细信息,请参阅成员资格测试操作,包括此声明
对于容器类型,例如list,tuple,set,frozenset,dict或collections.deque,表达式
x in y等效于any(x is e or x == e for e in y).
Python列表在C代码中定义.
static int
list_contains(PyListObject *a, PyObject *el)
{
Py_ssize_t i;
int cmp;
for (i = 0, cmp = 0 ; cmp == 0 && i < Py_SIZE(a); ++i)
cmp = PyObject_RichCompareBool(el, PyList_GET_ITEM(a, i),
Py_EQ);
return cmp;
}
Run Code Online (Sandbox Code Playgroud)
可以相当直接地看到这段代码循环遍历列表中的项目并在第一次相等(Py_EQ)之间进行比较el并PyList_GET_ITEM(a, i)返回1 时停止.
这并不等效,因为any需要额外的函数调用,生成器表达式和其他东西。
>>> mode = "access"
>>> allowed_modes =["access", "read", "write"]
>>>
>>> def f1():
... mode in allowed_modes
...
>>> def f2():
... any(mode == x for x in allowed_modes)
...
>>>
>>>
>>> import dis
>>> dis.dis
dis.dis( dis.disassemble( dis.disco( dis.distb(
>>> dis.dis(f1)
2 0 LOAD_GLOBAL 0 (mode)
3 LOAD_GLOBAL 1 (allowed_modes)
6 COMPARE_OP 6 (in)
9 POP_TOP
10 LOAD_CONST 0 (None)
13 RETURN_VALUE
>>> dis.dis(f2)
2 0 LOAD_GLOBAL 0 (any)
3 LOAD_CONST 1 (<code object <genexpr> at 0x7fb24a957540, file "<stdin>", line 2>)
6 LOAD_CONST 2 ('f2.<locals>.<genexpr>')
9 MAKE_FUNCTION 0
12 LOAD_GLOBAL 1 (allowed_modes)
15 GET_ITER
16 CALL_FUNCTION 1 (1 positional, 0 keyword pair)
19 CALL_FUNCTION 1 (1 positional, 0 keyword pair)
22 POP_TOP
23 LOAD_CONST 0 (None)
26 RETURN_VALUE
>>>
Run Code Online (Sandbox Code Playgroud)
这比方法本身的python源代码更具启发性,但是这里是__contains__for列表的源代码,并且循环在C中进行,这可能比Python循环要快。
一些计时数字证实了这一点。
>>> import timeit
>>> timeit.timeit(f1)
0.18974408798385412
>>> timeit.timeit(f2)
0.7702703149989247
>>>
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
1679 次 |
| 最近记录: |