Python重载原语

Python重载原语,python,overloading,forbiddenfruit,Python,Overloading,Forbiddenfruit,我正在尝试重载字符串内置的一些方法。 我知道这方面没有真正合法的用例,但这种行为仍然困扰着我,因此我想对这里发生的事情进行解释: 使用Python2和禁止水果模块 >>> from forbiddenfruit import curse >>> curse(str, '__repr__', lambda self:'bar') >>> 'foo' 'foo' >>> 'foo'.__repr__() 'bar' 如您所见,

我正在尝试重载字符串内置的一些方法。 我知道这方面没有真正合法的用例,但这种行为仍然困扰着我,因此我想对这里发生的事情进行解释:

使用Python2和
禁止水果
模块

>>> from forbiddenfruit import curse
>>> curse(str, '__repr__', lambda self:'bar')
>>> 'foo'
'foo'
>>> 'foo'.__repr__()
'bar'
如您所见,
\uuuu repr\uuu
函数已成功重载,但在请求表示时实际上没有调用。为什么呢

那么,您将如何获得预期的行为:

>>> 'foo'
'bar'
>>> 'foo'
'bar'

设置自定义环境没有任何限制,如果需要重建python,那就这样做吧,但我真的不知道从哪里开始,我仍然希望有一个更简单的方法:)

首先要注意的是,无论
禁止水果
在做什么,它都不会影响
repr
。这并不是
str
的特例,它的工作原理不是这样的:

import forbiddenfruit

class X:
    repr = None

repr(X())
#>>> '<X object at 0x7f907acf4c18>'

forbiddenfruit.curse(X, "__repr__", lambda self: "I am X")

repr(X())
#>>> '<X object at 0x7f907acf4c50>'

X().__repr__()
#>>> 'I am X'

X.__repr__ = X.__repr__

repr(X())
#>>> 'I am X'
所以我们知道,有点反斜视的是,其他的事情正在发生

这是:

和(省略部分):

重要的一点是,它不是在
dict
中查找,而是查找“cached”
tp_repr
属性

当您使用类似于
类型的内容设置属性时

static int
type_setattro(PyTypeObject *type, PyObject *name, PyObject *value)
{
    if (!(type->tp_flags & Py_TPFLAGS_HEAPTYPE)) {
        PyErr_Format(
            PyExc_TypeError,
            "can't set attributes of built-in/extension type '%s'",
            type->tp_name);
        return -1;
    }
    if (PyObject_GenericSetAttr((PyObject *)type, name, value) < 0)
        return -1;
    return update_slot(type, name);
}
这实际上很容易使用:

sys.displayhook
在计算交互式Python会话中输入的值的结果时调用。可以通过将另一个单参数函数指定给
sys.displayhook
来自定义这些值的显示

下面是一个例子:

import sys

old_displayhook = sys.displayhook
def displayhook(object):
    if type(object) is str:
        old_displayhook('bar')
    else:
        old_displayhook(object)

sys.displayhook = displayhook
然后。。。(!)


关于为什么
repr
会被如此缓存的哲学观点,首先考虑:

1 + 1

如果在调用之前必须在字典中查找
\uuuuu add\uuuu
,这将是一件痛苦的事情,因为CPython的速度很慢,所以CPython决定将查找缓存到标准dunder(双下划线)方法<代码>\uuuu repr\uuuu
就是其中之一,即使需要优化查找的情况不太常见。这对于快速格式化(
'%s'%s
)仍然很有用。

您试图解决什么问题(这使您想重载内置方法)?@goncalopp的可能重复:我试图做的是让一个运行的python shell,其中为任何字符串调用的repr被我的自定义方法替换。它不必在qny程序中使用,因为qny程序必须在任何其他python解释器上运行,所以正如我所说的,如果我知道方法的话,用猴子修补我自己的python就可以了。@njzk2:我不想在实例上重写该方法,而是在类上重写该方法。我试过使用BankeddenFruit,因为python不允许我对str这样的内置类型执行此操作。一旦调用了
诅咒…
str.。\uuuu dict\uuuu[''.\uu repr\uu'.]告诉您什么?这是!谢谢你,维德拉克!这是完美的,有很多解释。我只说了一半,但这确实比我期望的要多。这确实是@TerrenceBrannon,我在这个答案中解释了为什么没有。很可能我还不够清楚,所以如果你能解释一下为什么你认为我说了其他的话,这将真的有助于我解决任何含糊不清的问题。@Veedrac,你介意看看这个问题吗,我想知道我想做的是否可能谢谢
}
static int
type_setattro(PyTypeObject *type, PyObject *name, PyObject *value)
{
    if (!(type->tp_flags & Py_TPFLAGS_HEAPTYPE)) {
        PyErr_Format(
            PyExc_TypeError,
            "can't set attributes of built-in/extension type '%s'",
            type->tp_name);
        return -1;
    }
    if (PyObject_GenericSetAttr((PyObject *)type, name, value) < 0)
        return -1;
    return update_slot(type, name);
}
>>> 'foo'
'bar'
import sys

old_displayhook = sys.displayhook
def displayhook(object):
    if type(object) is str:
        old_displayhook('bar')
    else:
        old_displayhook(object)

sys.displayhook = displayhook
'foo'
#>>> 'bar'

123
#>>> 123
1 + 1