在Python中1 + 1可以等于3吗?

Can 1 + 1 be equal to 3 in python?

本问题已经有最佳答案,请猛点这里访问。

在继续之前,我知道人们永远不应该这样做。这个问题纯粹是为了教育目的;我进行这个练习是为了更好地理解Python的内部,即ctypes以及它们如何工作。

我知道在python中更改整数的值相对容易。实际上,你可以通过处理内部的问题来做很多事情。从C API参考中,

The current implementation keeps an array of integer objects for all
integers between -5 and 256, when you create an int in that range you
actually just get back a reference to the existing object. So it
should be possible to change the value of 1. I suspect the behaviour
of Python in this case is undefined. :-)

考虑到1的值是由cpython缓存的,这样做应该相对容易(或者至少可能)。经过一番周密的挖掘,我发现埃多克斯1〔0〕才是我要去的地方。然而,我尝试的大多数方法都会导致segfault。我通过改变2的值接近了。

1
2
3
4
5
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
2
3
4
5
6
7
8
>>> 1 + 1
1

>>> 1 + 2
1

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

我尝试过类似的方法,但最终失败的是Abarnet的internals模块。在python中有没有办法让1 + 13进行评估?或者"1"是如此重要,以至于没有办法在不打断我的口译员的情况下完成这项工作?


disclaimer回答:这两个refers CPython只读;也可能会错过了希腊的问题…

我能够(有点)写一本市实现Python的C扩展。

Objects/intobject.c有struct PyInt_Type安信息。这场tp_as_numberis a table of the nb_add算子函数,这是场:加法算子

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

PyInt_Type暴露的岩石和全局变量,可以用在retrieved dlsym在Unix / GetProcAddressWINAPI:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
#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);
}

全保市的原代码和内部变量的代码,《纽约avoids此前segfaults治疗:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
>>> # 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