代码之家  ›  专栏  ›  技术社区  ›  cs95 abhishek58g

在python中1+1可以等于3吗?[重复]

  •  3
  • cs95 abhishek58g  · 技术社区  · 7 年前

    这个问题已经有了答案:

    在继续之前,我知道一个人应该 从未 这样做。这个问题纯粹是为了教育目的;我进行这个练习是为了更好地理解python的内部 ctypes ,以及它们的工作方式。

    我知道在python中更改整数的值相对容易。实际上,有一个 whole lot you can do 弄乱内部结构。从 C API reference ,

    当前实现为所有 介于-5和256之间的整数,当您在该范围内创建一个int时 实际上,只需返回对现有对象的引用。所以它 应该可以更改1的值。我怀疑他的行为 在本例中,未定义python的。-)

    考虑到cpython缓存了1的值,这样做应该相对容易(或者至少可能)。经过一番调查,我发现 C型 是个好办法。然而,我尝试的大多数结果都是segfault。我通过改变2的值来接近。

    import ctypes
    def deref(addr, typ):
         return ctypes.cast(addr, ctypes.POINTER(typ))
    
    deref(id(2), ctypes.c_int)[6] = 1
    

    1+1现在给出了错误的结果(朝着正确的方向迈出了一步),但我无法将其计算为“3”:

    >>> 1 + 1
    1
    
    >>> 1 + 2
    1
    
    >>> 1 + 3
    [1]    61014 segmentation fault  python3.6
    

    我也尝试过类似的事情,最后都以失败告终 internals 模块。有什么办法 1 + 1 评估到 3 在蟒蛇?或者“1”是如此重要以至于没有办法让我的翻译不被分离?

    1 回复  |  直到 7 年前
        1
  •  2
  •   meowgoesthedog    7 年前

    免责声明:此答案仅指cpython;我可能还没有抓住问题的要点……

    我可以通过用c编写一个python扩展来实现这一点。

    Objects/intobject.c 有一个信息结构 PyInt_Type . 它的 tp_as_number 字段是运算符函数的表, nb_add 其中字段是加法运算符:

    // the function in the same file that nb_add points to
    static PyObject *
    int_add(PyIntObject *v, PyIntObject *w)
        ...
    

    平梯型 是一个公开的全局变量,可以使用 dlsym 在UNIX中 GetProcAddress 在WinAPI:

    #include <dlfcn.h>
    
    ...
    
    // symbol look-up from the Python extension
    void* addr = dlsym(RTLD_DEFAULT, "PyInt_Type");
    
    // pointer to PyInt_Type
    PyTypeObject *int_type = addr;
    
    // pointer to int_as_number (PyInt_Type.tp_as_number)
    PyNumberMethods *int_funcs = int_type->tp_as_number;
    
    // pointer to int_add (tp_as_number->nb_add)
    int_add_orig = int_funcs->nb_add;
    
    // override this with a custom function
    int_funcs->nb_add = (binaryfunc)int_add_new;
    
    ...
    
    // custom add function
    PyObject *int_add_new(PyIntObject *v, PyIntObject *w)
    {
        long a = PyInt_AS_LONG(v);
        long b = PyInt_AS_LONG(w);
    
        // 1 + 1 = 3 special case
        if (a == 1 && b == 1) {
            return PyInt_FromLong(3);
        }
    
        // for all other cases default to the
        // original add function which was retrieved earlier
        return int_add_orig((PyObject *)v, (PyObject *)w);
    }
    

    通过保留所有原始代码和内部变量,新代码避免了以前遇到的segfaults:

    >>> # load the extension
    
    >>> import [...]
    
    >>> 1 + 1
    2
    
    >>> # call the extension function which overloads the add operator
    
    >>> 1 + 1
    3
    
    >>> 1 + 0
    1
    
    >>> 1 + 2
    3
    
    >>> 1 + 3
    4