Python中判斷子串存在的性能比較及分析總結

 更新時間:2019年06月23日 08:40:04   作者:棲遲于一丘   我要評論
這篇文章主要給大家總結介紹了Python中判斷子串存在的性能比較及分析的相關資料,文中通過示例代碼介紹的非常詳細,對大家學習或者使用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級的,所以兩種方式都要對函數調用所需的空間的。

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

相關文章

  • PyCharm刷新項目(文件)目錄的實現

    PyCharm刷新項目(文件)目錄的實現

    今天小編就為大家分享一篇PyCharm刷新項目(文件)目錄的實現,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-02-02
  • Python中使用動態變量名的方法

    Python中使用動態變量名的方法

    這篇文章主要介紹了Python中使用動態變量名的方法,需要的朋友可以參考下
    2014-05-05
  • python中如何使用分步式進程計算詳解

    python中如何使用分步式進程計算詳解

    抽了點時間體驗了一把python分布式進程,有點像分布式計算的意思,這篇文章主要給大家介紹了關于python中如何使用分步式進程計算的相關資料,需要的朋友可以參考下
    2019-03-03
  • python中reduce()函數的使用方法示例

    python中reduce()函數的使用方法示例

    reduce() 函數會對參數序列中元素進行累積,下面這篇文章主要給大家介紹了關于python中reduce()函數的使用方法,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面來一起看看吧。
    2017-09-09
  • python面試題之列表聲明實例分析

    python面試題之列表聲明實例分析

    這篇文章主要介紹了python面試題之列表聲明,結合實例形式分析了Python列表的聲明、計算相關操作技巧,需要的朋友可以參考下
    2019-07-07
  • Python操作MongoDB詳解及實例

    Python操作MongoDB詳解及實例

    這篇文章主要介紹了Python操作MongoDB詳解及實例的相關資料,需要的朋友可以參考下
    2017-05-05
  • 詳解Python3除法之真除法、截斷除法和下取整對比

    詳解Python3除法之真除法、截斷除法和下取整對比

    這篇文章主要介紹了詳解Python3除法之真除法、截斷除法和下取整對比,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2019-05-05
  • Python3.4學習筆記之常用操作符,條件分支和循環用法示例

    Python3.4學習筆記之常用操作符,條件分支和循環用法示例

    這篇文章主要介紹了Python3.4常用操作符,條件分支和循環用法,結合實例形式較為詳細的分析了Python3.4常見的數學運算、邏輯運算操作符,條件分支語句,循環語句等功能與基本用法,需要的朋友可以參考下
    2019-03-03
  • python 字典操作提取key,value的方法

    python 字典操作提取key,value的方法

    這篇文章主要介紹了python 字典操作提取key,value的方法,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2019-06-06
  • python實現讀取大文件并逐行寫入另外一個文件

    python實現讀取大文件并逐行寫入另外一個文件

    下面小編就為大家分享一篇python實現讀取大文件并逐行寫入另外一個文件,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2018-04-04

最新評論

湖北11选5走势图爱彩乐 股票分析群 熊猫四川麻将有挂吗 加拿大28是人工控制的吗 3d字谜图库 qq麻将 黑龙江省36选七的开奖号码 捕鱼王怎么赚钱 正宗天津麻将安卓下载 大庆棋牌大厅 上海十一选五分布走势 华东15选5开奖30期结果 大富翁app下载安装 网盛棋牌app下载平台 打麻将下载免费下载 快乐十分钟直播 福彩幸运3D走势图