在创建实例后,尝试更改实例上的__unicode__
方法会在Python 2.5和2.6上产生不同的结果。
这是一个测试脚本:
class Dummy(object):
def __unicode__(self):
return u'one'
def two(self):
return u'two'
d = Dummy()
print unicode(d)
d.__unicode__ = d.two
print unicode(d)
print d.__unicode__()
在Python 2.5上,这会产生
one
two
two
也就是说,更改实例的__unicode__
也会更改unicode(instance)
在Python 2.6上,这会产生
one
one
two
因此,更改后,unicode(instance)
和instance.__unicode__()
会返回不同的结果。
为什么呢?我怎样才能在Python 2.6上使用它?
(对于它的价值,这里的用例是我想为给定类的所有子类的__unicode__
的输出附加一些内容,而不必修改子类的代码。)
编辑以使用例更清晰
我有A类,它有许多子类。这些子类定义了简单的__unicode__
方法。我想添加逻辑,以便对于A类子类的实例,unicode(实例)得到一些固定到最后的东西。为了保持代码简单,并且因为有许多子类我不想改变,我宁愿避免编辑子类代码。
这实际上是在Python 2.5中运行的现有代码。它是这样的:
class A(object):
def __init__(self):
self._original_unicode = self.__unicode__
self.__unicode__ = self.augmented_unicode
def augmented_unicode(self):
return self._original_unicode() + u' EXTRA'
这段代码不再适用于2.6。有关如何在不修改子类代码的情况下实现此目的的任何建议(如果答案涉及元类,请注意,类A本身是另一个类的子类 - django.db.models.Model - 具有相当精细的元类。)
答案 0 :(得分:2)
编辑:响应OP的评论:添加一个间接层可以让您在每个实例的基础上更改unicode
的行为:
class Dummy(object):
def __unicode__(self):
return self._unicode()
def _unicode(self):
return u'one'
def two(self):
return u'two'
d = Dummy()
print unicode(d)
# one
d._unicode = d.two
print unicode(d)
# two
print d.__unicode__()
# two
答案 1 :(得分:2)
您似乎不允许monkey-patch protocol methods(以双下划线开头和结尾的那些):
注意强>
在实践中还有另一个例外 我们这里没有处理过。虽然 你可以用实例覆盖方法 属性(对猴子非常有用) 用于测试目的的修补方法) 你不能用Python做到这一点 协议方法。这些都是'神奇的 名称开头和结尾的方法 双下划线。调用时 通过Python解释器,他们是 直接看了上课 不在实例上(但如果你 直接查找它们 - 例如 x。 repr - 正常属性查找 规则适用)。
在这种情况下,除非你可以使用~unutbu's answer,否则你可能会陷入困境。
编辑:或者,您可以让基类__unicode__
方法在实例对象的dict中搜索__unicode__
属性。如果它存在,则在实例对象上定义__unicode__
,并且类方法调用实例方法。否则,我们回到__unicode__
的类定义。
我认为这可以让您现有的子类代码无需任何更改即可运行。但是,如果派生类想要调用类实现,它会变得很难看 - 你需要小心避免无限循环。在这个例子中我没有实现这样的黑客攻击;只是评论了他们。
import types
class Dummy(object):
def __unicode__(self):
func = self.__dict__.get("__unicode__", None)
if func:
// WARNING: if func() invokes this __unicode__ method directly,
// an infinite loop could result. You may need an ugly hack to guard
// against this. (E.g., set a flag on entry / unset the flag on exit,
// using a try/finally to protect against exceptions.)
return func()
return u'one'
def two(self):
return u'two'
d = Dummy()
print unicode(d)
funcType = type(Dummy.__unicode__)
d.__unicode__ = types.MethodType(Dummy.two, d)
print unicode(d)
print d.__unicode__()
使用Python 2.6进行测试会产生以下输出:
> python dummy.py
one
two
two
答案 2 :(得分:0)
看起来Dan对于猴子修补协议方法是正确的,这是Python 2.5和Python 2.6之间的变化。
我的修复结果是在类而不是实例上进行更改:
class A(object):
def __init__(self):
self.__class__.__unicode__ = self.__class__.augmented_unicode