python 字符串插值

发布于 2024-08-22 15:56:15 字数 1828 浏览 1 评论 0原文

什么会产生以下行为?

>>> 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

感谢所有建议。

我不认为这会有更多帮助,但对于好奇的读者(和喜欢冒险的Python专家)来说,这是该对象的实现:

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)

这就是我们创建对象msg的方式:

>>> msg = Message('another message', 'mydomain', default='my message')

Zope包版本和使用的代码是:

编辑信息:

  • 添加/更新了被覆盖的方法的名称
  • 添加了一些更多信息(python 版本和次要版本) info)
  • 更新了一些错误信息(`msg`类基于`unicode`类而不是`basestring`)
  • 添加了所使用的类的实际实现

What could generate the following behavior ?

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

But:

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

More info:

  • my msg object is inherited from unicode.
  • the methods __str__/__unicode__/__repr__ methods were overridden to return the string 'my message'.
  • the msg object was initialised with the string 'another message'.
  • this is running on python 2.5
  • the variable msg was not changed between the tests
  • this is actually real doctest that is really giving these results.

I would like an solution that matches this doctest, with minimal fuss (especially around the actual inheritance):

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

Thanks for all suggestions.

I don't feel this will help more, but for curious readers (and adventurous pythonist), here's the implementation of the object:

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)

This is how we create the object msg:

>>> msg = Message('another message', 'mydomain', default='my message')

Zope packages version and code used are:

EDIT INFO:

  • added/updated the names of the methods that were overriden
  • added some more info (python version, and minor info)
  • updated some wrong info (the class of `msg` is based on `unicode` class and not `basestring`)
  • added the actual implementation of the class used

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

‖放下 2024-08-29 15:56:16

更新2:请找到原始答案,包括水平条下方展示 OP 描述的行为的类的简单示例。至于我在查询 Python 源代码(v. 2.6.4)的过程中能够推测出的内容:

文件 Include/unicodeobject.h 包含以下行(第 436-7 行)在我的(有点旧的)结帐中):

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

这在格式化代码中随处可见,据我所知,这意味着在字符串格式化期间,任何继承自 unicode 的对象都会以便可以直接使用其 unicode 字符串缓冲区,而无需调用任何 Python 方法。我确信就性能而言这是好的(并且非常符合于尔根在对此答案的评论中的猜想)。

对于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__() gets noparameter) :

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的对象...好吧,如果不看到它的代码我怎么知道???给我代码,我保证会考虑一下! 好吧,我正在考虑......到目前为止还没有想法。

Update 2: Please find the original answer, including a simple example of a class exhibiting the behaviour described by the OP, below the horizontal bar. As for what I was able to surmise in the course of my inquiry into Python's sources (v. 2.6.4):

The file Include/unicodeobject.h contains the following to lines (nos. 436-7 in my (somewhat old) checkout):

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

This is used all over the place in the formatting code, which, as far as I can tell, means that during string formatting, any object which inherits from unicode will be reached into so that its unicode string buffer may be used directly, without calling any Python methods. Which is good as far as performance is concerned, I'm sure (and very much in line with Juergen's conjecture in a comment on this answer).

For the OP's question, this probably means that making things work the way the OP would like them to may only be possible if something like Anurag Uniyal's wrapper class idea is acceptable for this particular use case. If it isn't, the only thing which comes to my mind now is to wrap objects of this class in str / unicode wherever their being interpolated into a string... ugh. (I sincerely hope I'm just missing a cleaner solution which someone will point out in a minute!)


(Update: This was posted about a minute before the OP included the code of his class, but I'm leaving it here anyway (1) for the conjecture / initial attempt at an explanation below the code, (2) for a simple example of how to produce this behaviour (Anurag Uniyal has since provided another one calling unicode's constructor directly, as opposed to via super), (3) in hope of later being able to edit in something to help the OP in obtaining the desired behaviour.)

Here's an example of a class which actually works like what the OP describes (Python 2.6.4, it does produce a deprecation warning -- /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'

A couple of interactions in 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

Apparently string interpolation treats this object as an instance of unicode (directly calling the unicode implementation of __str__), whereas the other functions treat it as an instance of Foo. How this happens internally and why it works like this and whether it's a bug or a feature, I really don't know.

As for how to fix the OP's object... Well, how would I know without seeing its code??? Give me the code and I promise to think about it! Ok, I'm thinking about it... No ideas so far.

〆一缕阳光ご 2024-08-29 15:56:16

所以问题是像下面的类的行为很奇怪

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

我不确定为什么会发生这种情况或如何修复它,但通过包装 Msg 进行了非常粗略的尝试,但不确定它是否有助于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

So problem is class like to something below behaves weirdly

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

this prints

my message
my message
another message

I am not sure why this happens or how to fix it, but a very crude attempt by wrapping Msg, but not sure it will help in OP's problem

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

output:

my message
my message
my message
咋地 2024-08-29 15:56:16

我认为你的问题是你正在尝试扩展内置的。内置函数不会调用魔术 __ 方法。我认为你必须做某种包装和委托,就像这样(未经测试)(也许 Anurag 打败了我):

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 - 看起来内置函数的子类会调用 __ 方法 do

>>> 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
'***'

所以肯定存在一些不一致的情况......

I think your problem is that you are trying to extend a built-in. Magic __ methods don't get called for builtins. I think you will have to do some kind of wrap-and-delegate, like this (untested) (maybe Anurag beat me to the punch):

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) 

Update 1 - it seems that __ methods do get called for subclasses of builtins

>>> 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
'***'

So there is definitely some inconsistency going on...

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文