首先要注意的是,无论forbiddenfruit
在做什么,它都不会影响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'
我最近发现a much simpler way of doing what forbiddenfruit
does由于在一个帖子中HYRY:
import gc
underlying_dict = gc.get_referents(str.__dict__)[0]
underlying_dict["__repr__"] = lambda self: print("I am a str!")
"hello".__repr__()
#>>> I am a str!
repr("hello")
#>>> "'hello'"
因此,我们知道,有些anticlimactically ,还有其他事情正在发生。
这里的the source for builtin_repr
:
builtin_repr(PyModuleDef *module, PyObject *obj)
/*[clinic end generated code: output=988980120f39e2fa input=a2bca0f38a5a924d]*/
{
return PyObject_Repr(obj);
}
而对于PyObject_Repr
(省略的部分):
PyObject *
PyObject_Repr(PyObject *v)
{
PyObject *res;
res = (*v->ob_type->tp_repr)(v);
if (res == NULL)
return NULL;
}
重要的一点是,而不是看着在dict
中,它查找“缓存的”tp_repr
属性。
Here's what happens当你设置像TYPE.__repr__ = new_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);
}
第一部分是阻止你修改的东西内置类型。然后它一般地设置属性(PyObject_GenericSetAttr
),并且关键地更新插槽。
如果你对如何工作感兴趣,it's available here。关键点是:
它不是一个导出的函数和
它修改PyTypeObject
实例本身
所以复制它需要黑客进入PyTypeObject
类型本身。
如果你想这样做,最简单的尝试可能是(暂时?)在str
类上设置type->tp_flags & Py_TPFLAGS_HEAPTYPE
。这将允许正常设置属性。 当然,不能保证这不会导致您的解释器崩溃。
这不是我想要做的(特别是不通过),除非我真的要,所以我给你提供一个捷径。
你写:
然后,你会怎么做才能获得预期的行为:使用sys.displayhook
>>> 'foo'
'bar'
这其实很简单:
sys.displayhook
是要求评估在交互中输入的expression的结果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
然后......
'foo'
#>>> 'bar'
123
#>>> 123
论的哲学观点,为什么repr
会为这样的缓存(!) ,首先考虑:
1 + 1
如果在调用之前必须在字典中查找__add__
会很痛苦,CPython会很慢,所以CPython决定将查找缓存到标准dunder(双下划线)方法。 __repr__
就是其中之一,即使不太常见也需要优化查找。这对保持格式化('%s'%s
)速度仍然很有用。
你试图解决什么问题(这使你想重载内置方法)? – goncalopp 2014-09-26 14:11:15
可能重复的[重写对一个实例的特殊方法](http://stackoverflow.com/questions/10376604/overriding-special-methods-on-an-instance) – njzk2 2014-09-26 15:11:33
@goncalopp:我想要做的是有一个正在运行的python shell,其中调用任何字符串的__repr__被我的自定义方法替换。它不必在qny程序中使用,它必须在任何其他python解释器上运行,所以如我所说,只要我知道如何做到这一点,对自己的python进行猴子修补就可以了。 – Centime 2014-09-26 16:00:47