结合我和 @khelwood 的评论:
简短概括:
当分析两个比较的字节码时,它揭示了'time'
和'time'
字符串被分配到相同的对象上。因此,一个提前进行的身份检查(在 C 级别)是增加比较速度的原因。
同一对象赋值的原因是,作为一项实现细节,CPython 会将只包含“名称字符”(即字母和下划线字符)的字符串内部化。这使得对象的身份检查成为可能。
字节码:
import dis
In [24]: dis.dis("'time'=='time'")
1 0 LOAD_CONST 0 ('time') # <
2 LOAD_CONST 0 ('time') # <
4 COMPARE_OP 2 (==)
6 RETURN_VALUE
In [25]: dis.dis("'time'=='1234'")
1 0 LOAD_CONST 0 ('time') # <
2 LOAD_CONST 1 ('1234') # <
4 COMPARE_OP 2 (==)
6 RETURN_VALUE
作业时间安排:
在时间测试中,使用赋值操作也可以看到“加速”效果。将两个变量分别赋值(和比较)为相同的字符串,比将两个变量分别赋值(和比较)为不同的字符串更快。这进一步支持假设底层逻辑是执行对象比较。下一节将对此进行确认。
In [26]: timeit.timeit("x='time'; y='time'; x==y", number=1000000)
Out[26]: 0.0745926329982467
In [27]: timeit.timeit("x='time'; y='1234'; x==y", number=1000000)
Out[27]: 0.10328884399496019
Python源代码:
正如@mkrieger1和@Masklinn在评论中提供的那样,unicodeobject.c的源代码首先执行指针比较,如果结果为True
,则立即返回。
int
_PyUnicode_Equal(PyObject *str1, PyObject *str2)
{
assert(PyUnicode_CheckExact(str1));
assert(PyUnicode_CheckExact(str2));
if (str1 == str2) {
return 1;
}
if (PyUnicode_READY(str1) || PyUnicode_READY(str2)) {
return -1;
}
return unicode_compare_eq(str1, str2);
}
附录:
- 参考答案 很好地说明了如何读取反汇编的字节码输出。由@Delgan提供
- 参考答案 很好地描述了CPython的字符串缓存技术。由@ShadowRanger提供
"toto" is "toto"
的值。很可能在同一语句中编译两个相同的字符串文字到同一个字符串对象。如果您的字符串是通过不同方式生成的,则可能会得到不同的结果。 - khelwood