您好,登錄后才能下訂單哦!
起步
對于子串搜索,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
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。