社区所有版块导航
Python
python开源   Django   Python   DjangoApp   pycharm  
DATA
docker   Elasticsearch  
aigc
aigc   chatgpt  
WEB开发
linux   MongoDB   Redis   DATABASE   NGINX   其他Web框架   web工具   zookeeper   tornado   NoSql   Bootstrap   js   peewee   Git   bottle   IE   MQ   Jquery  
机器学习
机器学习算法  
Python88.com
反馈   公告   社区推广  
产品
短视频  
印度
印度  
Py学习  »  Python

为什么比较python中匹配的字符串比不匹配的字符串更快?

Eric • 3 年前 • 1158 次点击  

以下是两个测量值:

timeit.timeit('"toto"=="1234"', number=100000000)
1.8320042459999968
timeit.timeit('"toto"=="toto"', number=100000000)
1.4517491540000265

如您所见,比较两个匹配的字符串比比较两个大小相同但不匹配的字符串要快。 这相当令人不安:在字符串比较期间,我认为Python正在逐个字符测试字符串,所以 "toto"=="toto" 测试的时间应该比 "toto"=="1234" 因为它需要四次测试,而非匹配比较则需要一次测试。也许比较是基于散列的,但在这种情况下,两种比较的计时应该相同。

为什么?

Python社区是高质量的Python/Django开发社区
本文地址:http://www.python88.com/topic/132159
 
1158 次点击  
文章 [ 2 ]  |  最新文章 3 年前
Riccardo Bucco
Reply   •   1 楼
Riccardo Bucco    3 年前

不是 总是 比较匹配字符串的速度更快。相反,比较共享相同id的字符串总是更快。身份确实是这种行为的原因(正如@S3DEV精辟地解释的那样)的一个证明是:

>>> x = 'toto'
>>> y = 'toto'
>>> z = 'totoo'[:-1]
>>> w = 'abcd'
>>> x == y
True
>>> x == z
True
>>> x == w
False
>>> id(x) == id(y)
True
>>> id(x) == id(z)
False
>>> id(x) == id(w)
False
>>> timeit.timeit('x==y', number=100000000, globals={'x': x, 'y': y})
3.893762200000083
>>> timeit.timeit('x==z', number=100000000, globals={'x': x, 'z': z})
4.205321462000029
>>> timeit.timeit('x==w', number=100000000, globals={'x': x, 'w': w})
4.15288594499998

比较具有相同id的对象总是更快(正如您从示例中注意到的,比较 x z 相比于 十、 y ,那是因为 十、 Z 不要共享相同的id)。

S3DEV
Reply   •   2 楼
S3DEV    3 年前

结合我的评论和@khelwood的评论:

TL;博士:
在分析字节码进行这两种比较时,它揭示了 'time' “时间” 字符串被指定给同一个对象。因此 身份检查 (C级)是比较速度提高的原因。

相同对象赋值的原因是 实施细节 ,CPython实习生字符串,仅包含“名称字符”(即alpha和下划线字符)。这将启用对象的身份检查。


字节码:

import dis

In [24]: dis.dis("'time'=='time'")
  1           0 LOAD_CONST               0 ('time')  # <-- same object (0)
              2 LOAD_CONST               0 ('time')  # <-- same object (0)
              4 COMPARE_OP               2 (==)
              6 RETURN_VALUE

In [25]: dis.dis("'time'=='1234'")
  1           0 LOAD_CONST               0 ('time')  # <-- different object (0)
              2 LOAD_CONST               1 ('1234')  # <-- different object (1)
              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和@masklin在他们的评论中所提供的帮助 source code 对于 unicodeobject.c 首先执行指针比较,如果 True ,立即返回。

int
_PyUnicode_Equal(PyObject *str1, PyObject *str2)
{
    assert(PyUnicode_CheckExact(str1));
    assert(PyUnicode_CheckExact(str2));
    if (str1 == str2) {                  // <-- Here
        return 1;
    }
    if (PyUnicode_READY(str1) || PyUnicode_READY(str2)) {
        return -1;
    }
    return unicode_compare_eq(str1, str2);
}

附录:

  • Reference answer 很好地演示了如何读取反汇编字节码输出。由@Delgan提供
  • Reference answer 这很好地描述了CPython的弦乐训练。《暗影游侠》中的Coutresy