Python中判斷子串存在的性能比較及分析總結(jié)
起步
對(duì)于子串搜索,Python提供了多種實(shí)現(xiàn)方式:in, find, index, __contains__,對(duì)其進(jìn)行性能比較:
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)
得到結(jié)果:
{
'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
}
從結(jié)果上 in 的搜索方式性能上最好。
知其然也要之其所以然,下面就對(duì)于這個(gè)結(jié)果進(jìn)行比較與分析。
in 與 __contains__ 比較
了解 Python 中協(xié)議的應(yīng)該知道,in 操作其實(shí)也是調(diào)用 __contains__ ,但為什么 in 比 __contains__ 明顯快了很多,明明它們最終調(diào)用的C語(yǔ)言函數(shù)是一樣的。
在 CPython 中,in 屬于操作符,它直接指向了 sq_contains 中的C級(jí)函數(shù)指針,而在 str 中的 sq_contains 直接指向了最終調(diào)用的C層函數(shù)。而 __contains__ 的調(diào)用方式,則需要先在 str 屬性中進(jìn)行 LOAD_ATTR 查找,然后再為 CALL_FUNCTION 創(chuàng)建函數(shù)調(diào)用所需的空間。
也就是說(shuō),in 直接指向了最終的C層函數(shù),一步到位,也不走Python虛擬機(jī)的函數(shù)調(diào)用,而 __contains__ 調(diào)用方式先屬性查找和Python函數(shù)調(diào)用的開(kāi)銷(xiāo);所以 str.__contains__(other) 的形式要慢得多。
一般來(lái)說(shuō),in 方式更快只使用 Python 內(nèi)置的C實(shí)現(xiàn)的類。對(duì)于用戶自定義類,因?yàn)樽罱K調(diào)用都是Python級(jí)的,所以兩種方式都要對(duì)函數(shù)調(diào)用所需的空間的。
find 與 index 的比較
find 與 index 的查找方式的區(qū)別僅僅只是 index 在子串不存在時(shí)會(huì)拋出異常。從源碼來(lái)看:
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); }
實(shí)現(xiàn)方式基本相同,所以在子串存在的時(shí)候,兩者的性能一致;而當(dāng)子串不存在時(shí),index 會(huì)設(shè)置異常,因此涉及異常棧的空間等異常機(jī)制,速度上也就慢了一些。
總結(jié)
in 的搜索方式性能最佳,可讀性也最好,屬最佳實(shí)踐。
好了,以上就是這篇文章的全部?jī)?nèi)容了,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,謝謝大家對(duì)腳本之家的支持。
擴(kuò)展閱讀
https://stackoverflow.com/questions/38400370/why-in-is-faster-than-contains
- python一些性能分析的技巧
- Python性能分析工具py-spy原理用法解析
- Python內(nèi)置類型性能分析過(guò)程實(shí)例
- Python性能分析工具Profile使用實(shí)例
- cProfile Python性能分析工具使用詳解
- 使用pycallgraph分析python代碼函數(shù)調(diào)用流程以及框架解析
- Python爬蟲(chóng)分析微博熱搜關(guān)鍵詞的實(shí)現(xiàn)代碼
- 使用bandit對(duì)目標(biāo)python代碼進(jìn)行安全函數(shù)掃描的案例分析
- python中delattr刪除對(duì)象方法的代碼分析
- python3中確保枚舉值代碼分析
- python如何做代碼性能分析
相關(guān)文章
python中數(shù)據(jù)庫(kù)like模糊查詢方式
這篇文章主要介紹了python中數(shù)據(jù)庫(kù)like模糊查詢方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-03-03Pythont特殊語(yǔ)法filter,map,reduce,apply使用方法
這篇文章主要介紹了Pythont特殊語(yǔ)法filter,map,reduce,apply使用方法,需要的朋友可以參考下2016-02-02python語(yǔ)法 range() 序列類型range
這篇文章主要介紹了python語(yǔ)法 range() 序列類型range,range是一種序列類型,range類型用于表示不可變的整數(shù)序列,下面小編整理了簡(jiǎn)單內(nèi)容,需要的小伙伴可以參考一下2022-01-01pyspark操作hive分區(qū)表及.gz.parquet和part-00000文件壓縮問(wèn)題
這篇文章主要介紹了pyspark操作hive分區(qū)表及.gz.parquet和part-00000文件壓縮問(wèn)題,針對(duì)問(wèn)題整理了spark操作hive表的幾種方式,需要的朋友可以參考下2021-08-08Python爬蟲(chóng)之urllib基礎(chǔ)用法教程
這篇文章主要為大家詳細(xì)介紹了Python爬蟲(chóng)1.1 urllib基礎(chǔ)用法教程,用于對(duì)Python爬蟲(chóng)技術(shù)進(jìn)行系列文檔講解,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-10-10淺談python中統(tǒng)計(jì)計(jì)數(shù)的幾種方法和Counter詳解
今天小編就為大家分享一篇淺談python中統(tǒng)計(jì)計(jì)數(shù)的幾種方法和Counter詳解,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2019-11-11