代码之家  ›  专栏  ›  技术社区  ›  maxschlepzig

python 3中的三向比较字符串

  •  4
  • maxschlepzig  · 技术社区  · 6 年前

    假设您希望优化(字节)字符串,比较用Python实现的密集型算法。因为中心代码路径包含此语句序列

    if s < t:
        # less than ...
    elif t < s:
        # greater than ...
    else:
        # equal ...
    

    将其优化为

    r = bytes_compare(s, t)
    if r < 0:
        # less than ...
    elif r > 0:
        # greater than ...
    else:
        # equal ...
    

    其中(假设) bytes_compare() 理想情况下只需拨打 three-way comparison C函数 memcmp() 这通常是相当好的优化。这将使字符串比较的数量减少一半。一个非常可行的优化,除非字符串是超短的。

    但是如何使用python 3到达那里呢?

    聚苯乙烯 :

    python 3删除了三向比较全局函数 cmp() 神奇的方法 __cmp__() 。即使有了python 2, bytes 班上没有 _凸轮轴位置 成员。

    ctypes 打包,直拨电话 memcmp()。 但是外部函数调用开销 C型 高得让人望而却步。

    1 回复  |  直到 6 年前
        1
  •  2
  •   maxschlepzig    6 年前

    __lt__() __eq__() memcmp() bytes Objects/bytesobject.c

    C extension

    #include <Python.h>
    static PyObject* cmp(PyObject* self, PyObject* args) {
        PyObject *a = 0, *b = 0;
        if (!PyArg_UnpackTuple(args, "cmp", 2, 2, &a, &b))
            return 0;
        if (!PyBytes_Check(a) || !PyBytes_Check(b)) {
            PyErr_SetString(PyExc_TypeError, "only bytes() strings supported");
            return 0;
        }
        Py_ssize_t n = PyBytes_GET_SIZE(a), m = PyBytes_GET_SIZE(b);
        char *s = PyBytes_AsString(a), *t = PyBytes_AsString(b);
        int r = 0;
        if (n == m) {
            r = memcmp(s, t, n);
        } else if (n < m) {
            r = memcmp(s, t, n);
            if (!r)
                r = -1;
        } else {
            r = memcmp(s, t, m);
            if (!r)
                r = 1;
        }
        return PyLong_FromLong(r);
    }
    static PyMethodDef bytes_util_methods[] = {
        { "cmp", cmp, METH_VARARGS, "Three way compare 2 bytes() objects." },
        {0,0,0,0} };
    static struct PyModuleDef bytes_util_def = {
        PyModuleDef_HEAD_INIT, "bytes_util", "Three way comparison for strings.",
        -1, bytes_util_methods };
    PyMODINIT_FUNC PyInit_bytes_util(void) {
        Py_Initialize();
        return PyModule_Create(&bytes_util_def);
    }
    

    gcc -Wall -O3 -fPIC -shared bytes_util.c -o bytes_util.so -I/usr/include/python3.6m
    

    >>> import bytes_util
    >>> bytes_util.cmp(b'foo', b'barx')
    265725
    

    memcmp ctypes