关于python:在新式类中替换__str__

Replacing __str__ in new-style class

本问题已经有最佳答案,请猛点这里访问。

我正在转换旧的python代码,并用新的样式类替换了一些类。问题是这破坏了替换__str__的行为,我不知道为什么。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class OldStyle():
    def __str__(self):
        return 'original'

old = OldStyle()
print old
old.__str__ = lambda: 'modified'
print old


class NewStyle(object):
    def __str__(self):
        return 'original'

new = NewStyle()
print new
new.__str__ = lambda: 'modified'
print new

我预料到了

1
2
3
4
original
modified
original
modified

但我得到了

1
2
3
4
original
modified
original
original

也就是说,新样式中没有正确地替换__str__。打印new.__str__会正确返回新lambda,但str(new)仍然不调用它。我认为这是某种方法查找缓存问题,但即使以前从未打印过对象,也会发生这种情况。

为什么会这样?我从来没有听说过这种行为差异,它只发生在__str__上,其他方法都被很好地取代了。


这在Python数据模型中的特殊方法名下进行了记录。明确地:

For instance, if a class defines a method named __getitem__, and x is an instance of this class, then x[i] is roughly equivalent to x.__getitem__(i) for old-style classes and type(x).__getitem__(x, i) for new-style classes.

我相信这使得新样式的类在这些操作方面更加高效,因为对于旧样式的类,python被强制查找属性,然后调用属性,对于新样式的类,python可以将其作为C结构的一部分引用,从而有效地将查找和调用推送到nativ中。E C代码。例如:

1
2
3
4
5
6
7
8
9
10
11
class Foo:
    def __add__(self,other):
        return 4 + other

class Bar(object):
    def __add__(self,other):
        return 4 + other

import timeit
print timeit.timeit('f + 5','from __main__ import Foo; f = Foo()')
print timeit.timeit('b + 5','from __main__ import Bar; b = Bar()')

对于我(python2.7.3,OS-X 10.5.8),新样式的类快了近4倍!

1
2
2.27801704407
0.602614879608

这项工作:

1
NewStyle.__str__ = lambda self: 'modified'

我们看到的似乎是__str__方法现在绑定到了类类型,而不是实例。我不知道为什么。您可以显式调用new.__str__()并获取被替换的方法,但是str(new)总是调用NewStyle.__str__(new)