python - python 中 1 + 1 可以等于 3 吗?

标签 python python-3.x internals

<分区>

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

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

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 缓存,执行此操作应该相对容易(或至少可能)。仔细研究之后,我发现 ctypes 是正确的选择。但是,我尝试的大部分内容都会导致段错误。我通过更改 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

我在 abarnert 的 internals 上尝试过类似的事情,但以失败告终。模块。有没有办法让 1 + 1 在 python 中计算为 3?还是“1”如此重要以至于如果不对我的解释器进行段错误就无法完成这项工作?

最佳答案

免责声明:此答案仅适用于 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)
    ...

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

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

>>> # 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

关于python - python 中 1 + 1 可以等于 3 吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53950215/

相关文章:

python - 循环时比较python中的列表

python - TreeViewColumn 标题中的 PyGTK 条目小部件

c - PROTECT 到底应该包裹什么?

python - 有没有办法编写创建和执行代码的 Python 脚本?

python - 删除非数字列表条目的最有效方法

python - 如何删除两列之间的重复项,但在各自的列中保留唯一值?

python - 文件 I/O 操作会释放 Python 中的 GIL 吗?

python-3.x - Python 3.5.2 中的 Openpyxl ImportError

hadoop - Mapreduce数据流内部

node.js - node.js 的内部结构。它实际上是如何工作的