在继续下去之前,我意识到一个人永远不应该这样做。这个问题纯粹是出于教育目的;我进行这个练习是为了更好地理解python的内部结构、ctype以及它们是如何工作的。
我知道在python中改变整数的值相对容易。事实上,你可以通过扰乱内部来做很多事情。从C API参考,
当前的实现为-5到256之间的所有整数保留一个整数对象数组,当您在该范围内创建一个int时,实际上只会返回对现有对象的引用。所以应该可以改变1的值。我怀疑Python在本例中的行为尚未定义。:-)
考虑到CPython缓存了1的值,这样做应该相对容易(或者至少是可能的)。经过一番探索,我发现ctypes
是一种选择。然而,我尝试的大多数结果都是一个错误。我通过改变2的值接近。
import ctypes
def deref(addr, typ):
return ctypes.cast(addr, ctypes.POINTER(typ))
deref(id(2), ctypes.c_int)[6] = 1
1现在给出了错误的结果(朝着正确的方向迈出了一步),但我无法将其计算为“3”:
>>> 1 + 1
1
>>> 1 + 2
1
>>> 1 + 3
[1] 61014 segmentation fault python3.6
我曾尝试过类似的事情,但最终以abarnert的内部模块
失败告终。有没有办法让python中的11
求值为3
?还是说“1”非常重要,以至于如果不给我的翻译出一个错误,就无法完成这项工作?
免责声明:这个答案仅指CPython;我可能也错过了问题的要点...
我通过用C语言编写Python扩展实现了这一点。
在对象/intject. c
中有一个info结构体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
是一个公开的全局变量,可以通过WinAPI中Unix/GetProc地址
中的dlsym
检索:
#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
最近我遇到一个问题: 我想计算各种数字的各种根,如下所示: 我知道的所有方法都不会产生有效的代码。 方法一: 打印值为28.0,而不是3.7798 方法2: 打印值为18.0 istead,为3.7798 方法三: 印刷值是5.99而不是6 有没有办法让你在20岁以下的时候工作? 编辑: 另一个建议的方法: 印刷品4
问题内容: 我可以在python中计算exp(1 + 2j)吗? 问题答案: 您需要此功能的复杂版本: 参见http://docs.python.org/library/cmath.html
问题内容: 我可以在Python中重置迭代器/生成器吗?我正在使用DictReader,并希望将其重置为文件的开头。 问题答案: 我看到很多建议itertools.tee的答案,但这忽略了文档中的一项重要警告: 此itertool可能需要大量辅助存储(取决于需要存储多少临时数据)。一般来说,如果一个迭代器使用大部分或全部的数据的另一个前开始迭代器,它是更快地使用代替。 基本上,是专为那些在两个(或
问题内容: 为什么在Python中等于?它不应该像那样抛出异常吗? 问题答案: Wikipedia对历史进行了有趣的报道,并对以下内容的价值有不同的看法: 至少从19世纪初期开始,辩论一直在进行。当时,大多数数学家都同意,直到1821年,柯西(Cauchy)以及诸如未定义形式的表格之类的表达式才被列出。在1830年代,利比里(Libri)发表了令人信服的论点,莫比乌斯(Möbius)站在他身边。
问题内容: 找不到更好的标题标题的方法,请随时进行纠正。 我是Python的新手,目前正在尝试使用该语言。.我注意到,所有内置类型都不能用其他成员扩展。.例如,我想向该类型添加一个方法,但这会不可能。我意识到出于效率方面的考虑而设计这种方式,并且大多数内置类型都是用C实现的。 好吧,为什么我发现要覆盖此行为的一个原因是定义了一个新类,该类可以扩展但不执行任何操作。然后,我可以将变量分配给该新类,并
问题内容: 想要改善这篇文章吗? 提供此问题的详细答案,包括引文和答案正确的解释。答案不够详细的答案可能会被编辑或删除。 主持人注意: 请不要编辑代码或删除此声明。空格模式可能是问题的一部分,因此不应不必要地对其进行篡改。如果您处于“空白无关紧要”的阵营中,则应该能够原样接受代码。 有可能用JavaScript 评估吗? 这是一家大型科技公司提出的面试问题。它发生在两周前,但我仍在努力寻找答案。我