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


Posted in Python onJune 23, 2019

起步

对于子串搜索,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级的,所以两种方式都要对函数调用所需的空间的。

find 与 index 的比较

find 与 index 的查找方式的区别仅仅只是 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 会设置异常,因此涉及异常栈的空间等异常机制,速度上也就慢了一些。

总结

in 的搜索方式性能最佳,可读性也最好,属最佳实践。

好了,以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,谢谢大家对三水点靠木的支持。

扩展阅读

https://stackoverflow.com/questions/38400370/why-in-is-faster-than-contains

Python 相关文章推荐
python格式化字符串实例总结
Sep 28 Python
Python常见格式化字符串方法小结【百分号与format方法】
Sep 18 Python
Python之Scrapy爬虫框架安装及使用详解
Nov 16 Python
Python利用matplotlib.pyplot绘图时如何设置坐标轴刻度
Apr 09 Python
python 去除txt文本中的空格、数字、特定字母等方法
Jul 24 Python
python连接mongodb密码认证实例
Oct 16 Python
Python 3.8 新功能全解
Jul 25 Python
python中selenium库的基本使用详解
Jul 31 Python
python接口自动化之ConfigParser配置文件的使用详解
Aug 03 Python
python自动化测试三部曲之unittest框架的实现
Oct 07 Python
python 读取yaml文件的两种方法(在unittest中使用)
Dec 01 Python
python3 实现mysql数据库连接池的示例代码
Apr 17 Python
树莓派与PC端在局域网内运用python实现即时通讯
Jun 22 #Python
树莓派采用socket方式文件传输(python)
Jun 22 #Python
树莓派用python中的OpenCV输出USB摄像头画面
Jun 22 #Python
树莓派使用USB摄像头和motion实现监控
Jun 22 #Python
树莓派动作捕捉抓拍存储图像脚本
Jun 22 #Python
python+openCV利用摄像头实现人员活动检测
Jun 22 #Python
树莓派实现移动拍照
Jun 22 #Python
You might like
预告映像公开!第1章续篇剧场版动画《Princess Principal Crown Handler》4月10日上映!
2020/03/06 日漫
PHP+MySQL5.0中文乱码解决方法
2006/11/20 PHP
PHP Stream_*系列函数
2010/08/01 PHP
PHP基于GD库的缩略图生成代码(支持jpg,gif,png格式)
2014/06/19 PHP
标准PHP的AES加密算法类
2015/03/12 PHP
PHP实现的限制IP投票程序IP来源分析
2016/05/04 PHP
原生JS实现Ajax通过GET方式与PHP进行交互操作示例
2018/05/12 PHP
php设计模式之观察者模式实例详解【星际争霸游戏案例】
2020/03/30 PHP
PHP实现抽奖功能实例代码
2020/06/30 PHP
分享一个自己写的table表格排序js插件(高效简洁)
2011/10/29 Javascript
让页面上两个div中的滚动条(滑块)同步运动示例
2013/08/07 Javascript
jQuery中removeAttr()方法用法实例
2015/01/05 Javascript
基于JavaScript实现瀑布流布局(二)
2016/01/26 Javascript
Jquery轮播效果实现过程解析
2016/03/30 Javascript
JavaScript_ECMA5数组新特性详解
2016/06/12 Javascript
jq实现左滑显示删除按钮,点击删除实现删除数据功能(推荐)
2016/08/23 Javascript
干货!教大家如何选择Vue和React
2017/03/13 Javascript
JavaScript编写棋盘覆盖代码详解
2017/08/28 Javascript
JS实现动态生成html table表格的方法分析
2018/07/11 Javascript
浅谈vue项目打包优化策略
2018/09/29 Javascript
微信小程序:数据存储、传值、取值详解
2019/05/07 Javascript
webpack项目使用eslint建立代码规范实现
2019/05/16 Javascript
vue element自定义表单验证请求后端接口验证
2019/12/11 Javascript
浅谈Python实现Apriori算法介绍
2017/12/20 Python
Python骚操作之动态定义函数
2019/03/26 Python
Python对称的二叉树多种思路实现方法
2020/02/28 Python
python按照list中字典的某key去重的示例代码
2020/10/13 Python
连卡佛中国官网:Lane Crawford中文站
2018/01/27 全球购物
在线购买廉价折扣书籍和小说:BookOutlet.com
2018/02/19 全球购物
西班牙在线宠物食品和配件商店:bitiba
2019/10/11 全球购物
澳大利亚家具商店:Freedom
2020/12/17 全球购物
几个常见的消息中间件(MOM)
2014/01/08 面试题
自我评价格式
2014/01/06 职场文书
决心书标准格式
2014/03/11 职场文书
党的群众路线教育实践活动对照检查剖析材料
2014/10/09 职场文书
mysql中整数数据类型tinyint详解
2021/12/06 MySQL