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