2010-02-22 71 views
13

什么会产生以下行为?python字符串插值

>>> print str(msg) 
my message 
>>> print unicode(msg) 
my message 

但是:

>>> print '%s' % msg 
another message 

更多信息:

  • msg对象从unicode继承。
  • 方法__str__/__unicode__/__repr__方法被覆盖返回字符串'my message'
  • msg对象初始化为字符串'another message'
  • 这是Python的2.5
  • 运行变量msg测试
  • 这其实是真正的文档测试是真的给这些结果之间没有改变。

我想,这个文档测试相匹配的解决方案,以最小的大惊小怪(特别是在实际的继承):

>>> print '%s' % msg 
my message 

感谢所有的建议。

我不觉得这会帮助更多的,但对于好奇的读者(和冒险pythonist),这里的实施对象:

class Message(zope.i18nmessageid.Message): 

    def __repr__(self): 
     return repr(zope.i18n.interpolate(self.default, self.mapping)) 

    def __str__(self): 
     return zope.i18n.interpolate(self.default, self.mapping) 

    def __unicode__(self): 
     return zope.i18n.interpolate(self.default, self.mapping) 

这是我们如何创建对象的信息:

Zope的软件包版本和代码使用
>>> msg = Message('another message', 'mydomain', default='my message') 

是:

编辑信息:

  • 添加/更新的是被重写
  • 添加一些更多的信息的方法的名称(Python版本,和小信息)
  • 更新了一些错误信息('msg`类是基于`unicode`类而不是`basestring`)
  • 添加了实际的实现类的离子用于
+3

@extraneon:这是蟒蛇2 .x:'print'是一个语句,basestring,unicode! – SilentGhost 2010-02-22 15:32:55

+1

在'print'之间更改'msg'变量的值会解释它 – van 2010-02-22 15:51:01

+1

您是否拥有该对象的实际代码? (或者说它的类。)如果你可以将它粘贴在这里,它会很有用... – 2010-02-22 15:54:07

回答

8

更新2:请找到原始答案,包括表现出由OP所描述的,下面的水平条的行为的一类的一个简单的例子。至于我在研究Python源代码的过程中能够猜测的东西(v.2.6.4):

文件Include/unicodeobject.h包含以下代码行(nos。436-7在我的(有点老)结账):

#define PyUnicode_AS_UNICODE(op) \            
     (((PyUnicodeObject *)(op))->str) 

这是各地使用的格式代码,地点中,据我所知,意味着字符串格式化过程中,它继承的任何对象从unicode将达到,以便它的unicode字符串缓冲区可以直接使用,而无需调用任何Python方法。就性能而言,这是很好的,我相信(并且非常符合Juergen对这个答案的评论中的猜测)。

对于OP的问题,这可能意味着,如果像Anurag Uniyal的包装类的想法可以接受这种特殊的用例,那么这可能意味着让事情按照OP希望他们的方式工作。如果不是这样,我现在唯一想到的就是将这个类的对象包装在str/unicode中,无论它们被插入到字符串中哪一个中......呃。 (我衷心希望我只是缺少一个更清洁的解决方案,有人会在一分钟内指出!)


更新:这被张贴大约一分钟前的OP包括他类的代码,但是我无论如何都要把它留在这里(1),因为猜测/初始尝试在代码下面的解释中,(2)关于如何产生这种行为的简单例子(Anurag Uniyal自此提供了另一个叫做unicode的构造函数直接,而不是通过super),(3)希望稍后能够编辑某些内容以帮助OP获得期望的行为。)

下面是其实际工作像什么OP描述类的示例(Python 2.6.4,它产生一个弃用警告 - /usr/bin/ipython:3: DeprecationWarning: object.__init__() takes no parameters):

class Foo(unicode): 
    def __init__(self, msg): 
     super(unicode, self).__init__(msg) 
    def __str__(self): return 'str msg' 
    def __repr__(self): return 'repr msg' 
    def __unicode__(self): return u'unicode msg' 

在IPython的一对夫妇的相互作用:

In [12]: print(Foo("asdf")) 
asdf 

In [13]: str(Foo("asdf")) 
Out[13]: 'str msg' 

In [14]: print str(Foo("asdf")) 
-------> print(str(Foo("asdf"))) 
str msg 

In [15]: print(str(Foo("asdf"))) 
str msg 

In [16]: print('%s' % Foo("asdf")) 
asdf 

显然,字符串插值将此对象视为unicode(直接调用__str__unicode实现)的实例,而其他函数将其视为Foo的实例。内部是如何发生的,为什么它像这样工作,以及它是一个错误还是一个功能,我真的不知道。

至于如何解决OP的对象......那么,我怎么会知道没有看到它的代码?给我的代码,我保证考虑一下! 好吧,我正在考虑这个问题......迄今为止还没有任何想法。

+0

在我看来,印刷已经制定了一些捷径 - 加快速度,我想。 Python具有(相对较快的)内部接口和(相对较慢的)外部接口。我猜,有人试图避免开销... – Juergen 2010-02-22 16:38:55

+0

@Juergen:包括一些信息,在答案中的来源看起来像现在...当然,似乎你是对的。 – 2010-02-22 17:15:13

+0

@Michal:感谢您的信息!作为一个系统,Python是相当干净的,但是(尽管我理解它并且也看到了一点点),但有时候一些快捷方式会在内部形成,从而获得很大的速度优势。在我看来,这是行得通的,因为这些快捷方式在99%的所有情况下都不可见......在另外1%的情况下,必须在此情况下制定解决方法。当然,当打败一个人时,它可能会令人惊讶,甚至令人讨厌... – Juergen 2010-02-23 10:56:38

6

所以,问题是阶级喜欢的东西下面的行为古怪

class Msg(unicode): 
    def __init__(self, s): 
     unicode.__init__(self, s) 

    __unicode__ = __repr__ = __str__ = lambda self: "my message" 

msg = Msg("another message") 
print str(msg) 
print unicode(msg) 
print "%s"%msg 

此打印

my message 
my message 
another message 

我不知道为什么出现这种情况或如何解决它,而是通过包装一个非常粗略的尝试消息,但不知道它会帮助OP的问题

class MsgX(object): 
    def __init__(self, s): 
     self._msg = Msg(s) 

    __unicode__ = __repr__ = __str__ = lambda self: repr(self._msg) 

msg = MsgX("another message") 
print str(msg) 
print unicode(msg) 
print "%s"%msg 

输出:

my message 
my message 
my message 
+0

我不能改变对unicode的继承。不过,谢谢你简单的例子。 – vaab 2010-02-22 18:05:49

+0

@vaab:如果您看看我给出的扩展答案,则添加'__getattr__'会将所有*将通过继承解析的访问器转发给包含的.msg属性。这在Python中是一个非常强大的习惯用法,并且将wrap-and-delegate与继承放在同等水平,并且耦合度较低。 – PaulMcG 2010-02-22 18:58:08

3

我认为你的问题是你试图扩展一个内置的。魔法__方法不会被调用builtin。我认为你将不得不做一些总结和委托的,像这样(未经)(也许阿努拉格打我冲):

class Message(object): 

    def __init__(self, strvalue, domain, default='my message'): 
     self.msg = zope.i18nmessageid.Message(strvalue,domain,default) 

    def __getattr__(self,attr): 
     return getattr(self.msg,attr) 

    def __repr__(self): 
     return repr(zope.i18n.interpolate(self.msg.default, self.msg.mapping)) 

    def __str__(self): 
     return zope.i18n.interpolate(self.msg.default, self.msg.mapping) 

    def __unicode__(self): 
     return zope.i18n.interpolate(self.msg.default, self.msg.mapping) 

更新1 - 似乎__方法获得呼吁内建

>>> class Z(int): 
... def __add__(self,other): return self*other 
... def __str__(self): return "***" 
... 
>>> a = Z(100) 
>>> a + 2 
200 
>>> a 
100 
>>> str(a) 
'***' 
>>> "%s" % a 
'***' 

的子类,所以肯定是有一些矛盾怎么回事...

+0

好主意,但这不起作用! ;)它对给定的doctest有效,但是这个类不再是'string'的一个实例,它会破坏我使用和需要使用的Python公共库中的一些其他C检查。我明天会更清楚。 – vaab 2010-02-22 19:02:21

+0

啊,你(或那些libs)正在使用isinstance,也许?现在这个类不再继承basestring?嗯,那些实例检查不会发生在做参数验证吗?这是一个很好的例子,说明为什么isinstance参数检查并不总是Python中最好的想法。 – PaulMcG 2010-02-22 19:48:58