Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/python-3.x/16.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Can 1+;1在python中等于3?_Python_Python 3.x_Internals - Fatal编程技术网

Can 1+;1在python中等于3?

Can 1+;1在python中等于3?,python,python-3.x,internals,Python,Python 3.x,Internals,在继续之前,我知道一个人永远不应该这样做。这个问题纯粹是为了教育目的;我做这个练习是为了更好地理解python的内部结构,ctypes,以及它们是如何工作的 我知道在python中更改整数的值相对容易。事实上,弄乱内部结构会有一个问题。从 当前实现为所有对象保留一个整数对象数组 介于-5和256之间的整数,当您在该范围内创建整数时 实际上,只需返回对现有对象的引用。所以 应该可以更改1的值。我怀疑这种行为 在本例中,Python的名称未定义。:-) 考虑到CPython缓存了1的值,这样做应该相

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

我知道在python中更改整数的值相对容易。事实上,弄乱内部结构会有一个问题。从

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

考虑到CPython缓存了1的值,这样做应该相对容易(或者至少是可能的)。经过一番探索,我发现
ctypes
是一个不错的选择。然而,我尝试的大多数结果都是SEGFULT。我通过改变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”:

我尝试过类似的事情,但最终以abarnert的模块失败告终。有没有办法让python中的
1+1
求值为
3
?或者“1”是如此重要,以至于如果不责怪我的翻译,就无法完成这项工作

免责声明:此答案仅指CPython;我可能也没有抓住问题的重点

我能够(有点)通过用C编写Python扩展来实现这一点

Objects/intobject.c
中有一个信息结构
PyInt\u 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)
    ...
PyInt_Type
是一个公开的全局变量,可以在Unix中使用
dlsym
在WinAPI中使用
GetProcAddress
进行检索:

#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);
}

看起来你本可以做的
deref(id(2),ctypes.c_int)[6]=3
。我投票将这个问题作为离题题来结束,因为一旦你开始尝试到这个程度,你可能几乎可以实现任何事情,大部分都没有任何目的或用途,而这并不是我们来这里的真正目的。@LightnessRacesinOrbit不够公平,这样做的唯一目的是理解内部的一切:-)它是未定义的行为。当然,这是未定义的行为。当你把2的值搞乱的时候,你怎么能指望别的呢?未定义行为在我的测试中的具体表现方式是,写入2个字符的
write
调用返回2,但2对象的值为3,并且3的字符数超出了应该打印的字符数。@Prune我理解。我记得在java中曾经问过一个类似的问题,在这之前,这个问题得到了很好的接受,所以我认为只要它被视为理解内部结构的教学工具,这就可以了。很高兴参加社区投票,但是我喜欢你回答这个问题的方式!虽然这不是我在发布问题时最初的想法,但知道如何通过实际修改源代码来做到这一点很酷。@coldspeed很好,没有完全修改Python的源代码(目标是避免直接修改,因为它使这个问题在概念上变得微不足道:D),而是在运行时修改其内部状态变量(与您尝试使用
deref
)没有什么不同。是的,我明白了,这使用了C API来编写扩展。我仍在消化这一点,请原谅我的无知:)
#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);
}
>>> # 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