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