Python 中几种判断子串存在的性能比较及分析

栏目: Python · 发布时间: 5年前

内容简介:对于子串搜索,Python提供了多种实现方式:得到结果:从结果上

起步

对于子串搜索,Python提供了多种实现方式: in , find , index , __contains__ ,对其进行性能比较:

import timeit

def in_(s, other):
    return other in s

def contains(s, other):
    return s.__contains__(other)

def find(s, other):
    return s.find(other) != -1

def index(s, other):
    try:
        s.index(other)
    except ValueError:
        return False
    return True

perf_dict = {
    'in:True': min(timeit.repeat(lambda: in_('superstring', 'str'))),
    'in:False': min(timeit.repeat(lambda: in_('superstring', 'not'))),
    '__contains__:True': min(timeit.repeat(lambda: contains('superstring', 'str'))),
    '__contains__:False': min(timeit.repeat(lambda: contains('superstring', 'not'))),
    'find:True': min(timeit.repeat(lambda: find('superstring', 'str'))),
    'find:False': min(timeit.repeat(lambda: find('superstring', 'not'))),
    'index:True': min(timeit.repeat(lambda: index('superstring', 'str'))),
    'index:False': min(timeit.repeat(lambda: index('superstring', 'not'))),
}

print(perf_dict)

得到结果:

{
    'in:True': 0.2763608000000001, 
    'in:False': 0.2794432, 
    '__contains__:True': 0.40546490000000013, 
    '__contains__:False': 0.4122471000000001, 
    'find:True': 0.497128, 
    'find:False': 0.4951530000000002, 
    'index:True': 0.5243821999999998, 
    'index:False': 0.8693923999999988
}

从结果上 in 的搜索方式性能上最好。

知其然也要之其所以然,下面就对于这个结果进行比较与分析。

in__contains__ 比较

了解 Python 中协议的应该知道, in 操作其实也是调用 __contains__ ,但为什么 in__contains__ 明显快了很多,明明它们最终调用的 C语言 函数是一样的。

在 CPython 中, in 属于操作符,它直接指向了 sq_contains 中的C级函数指针,而在 str 中的 sq_contains 直接指向了最终调用的C层函数。而 __contains__ 的调用方式,则需要先在 str 属性中进行 LOAD_ATTR 查找,然后再为 CALL_FUNCTION 创建函数调用所需的空间。

也就是说, in 直接指向了最终的C层函数,一步到位,也不走Python虚拟机的函数调用,而 __contains__ 调用方式先属性查找和Python函数调用的开销;所以 str.__contains__(other) 的形式要慢得多。

一般来说, in 方式更快只使用 Python 内置的C实现的类。对于用户自定义类,因为最终调用都是Python级的,所以两种方式都要对函数调用所需的空间的。

findindex 的比较

findindex 的查找方式的区别仅仅只是 index 在子串不存在时会抛出异常。从源码来看:

static PyObject *
unicode_find(PyObject *self, PyObject *args)
{
    /* initialize variables to prevent gcc warning */
    PyObject *substring = NULL;
    Py_ssize_t start = 0;
    Py_ssize_t end = 0;
    Py_ssize_t result;

    if (!parse_args_finds_unicode("find", args, &substring, &start, &end))
        return NULL;

    if (PyUnicode_READY(self) == -1)
        return NULL;

    result = any_find_slice(self, substring, start, end, 1);

    if (result == -2)
        return NULL;

    return PyLong_FromSsize_t(result);
}

static PyObject *
unicode_index(PyObject *self, PyObject *args)
{
    /* initialize variables to prevent gcc warning */
    Py_ssize_t result;
    PyObject *substring = NULL;
    Py_ssize_t start = 0;
    Py_ssize_t end = 0;

    if (!parse_args_finds_unicode("index", args, &substring, &start, &end))
        return NULL;

    if (PyUnicode_READY(self) == -1)
        return NULL;

    result = any_find_slice(self, substring, start, end, 1);

    if (result == -2)
        return NULL;

    if (result < 0) {
        PyErr_SetString(PyExc_ValueError, "substring not found");
        return NULL;
    }

    return PyLong_FromSsize_t(result);
}

实现方式基本相同,所以在子串存在的时候,两者的性能一致;而当子串不存在时, index 会设置异常,因此涉及异常栈的空间等异常机制,速度上也就慢了一些。


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

数据结构(C语言版)

数据结构(C语言版)

严蔚敏、吴伟民 / 清华大学出版社 / 2012-5 / 29.00元

《数据结构》(C语言版)是为“数据结构”课程编写的教材,也可作为学习数据结构及其算法的C程序设计的参数教材。 本书的前半部分从抽象数据类型的角度讨论各种基本类型的数据结构及其应用;后半部分主要讨论查找和排序的各种实现方法及其综合分析比较。其内容和章节编排1992年4月出版的《数据结构》(第二版)基本一致,但在本书中更突出了抽象数据类型的概念。全书采用类C语言作为数据结构和算法的描述语言。 ......一起来看看 《数据结构(C语言版)》 这本书的介绍吧!

Base64 编码/解码
Base64 编码/解码

Base64 编码/解码

HEX CMYK 转换工具
HEX CMYK 转换工具

HEX CMYK 互转工具