интерполяция строк python

что может вызвать следующее поведение ?

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

но:

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

Подробнее:

  • мой msg объект унаследовано от unicode.
  • методы __str__/__unicode__/__repr__ методы были переопределены, чтобы возвращать строку 'my message'.
  • the

3 ответов


обновление 2: пожалуйста, найдите оригинальный ответ, включая простой пример класса, демонстрирующего поведение, описанное OP, ниже горизонтальной полосы. Что касается того, что я смог предположить в ходе моего исследования источников Python (V. 2.6.4):

файл Include/unicodeobject.h содержит следующие строки (nos. 436-7 в моей (несколько старой) кассе):

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

это используется повсюду в коде форматирования, который, насколько я могу tell, означает, что во время форматирования строки любой объект, который наследуется от unicode будет достигнут, так что его строковый буфер unicode может использоваться напрямую, без вызова каких-либо методов Python. Что хорошо, что касается производительности, я уверен (и очень в соответствии с гипотезой Юргена в комментарии к этому ответу).

для вопроса OP это, вероятно, означает, что заставить вещи работать так, как OP хотел бы, чтобы они были возможны, только если что-то вроде Идея класса оболочки Anurag Uniyal приемлема для этого конкретного случая использования. Если это не так, единственное, что приходит мне на ум сейчас, чтобы обернуть объекты этого класса в str / unicode везде, где их интерполируют в строку... тьфу. (Я искренне надеюсь, что мне просто не хватает более чистого решения, которое кто-то укажет через минуту!)


(обновление: это было опубликовано за минуту до того, как ОП включил код своего класса, но я оставляю его здесь в любом случае (1) для гипотезы / начальной попытки объяснения ниже кода, (2) для простого примера того, как произвести это поведение (Anurag Uniyal с тех пор предоставил другой вызов unicodeконструктор непосредственно, в отличие от via 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 (прямо называя unicode реализация __str__), тогда как другие функции рассматривают его как экземпляр Foo. Как это происходит внутри и почему это работает так, и является ли это ошибкой или функцией, я действительно не знаю.

как для того чтобы исправить Объект ОП... Откуда мне знать, не видя кода??? Дайте мне код и я обещаю подумать об этом! Ок, я думаю об этом... Пока никаких идей.


Итак, проблема в том, что класс, как что-то ниже, ведет себя странно

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

Я думаю, ваша проблема в том, что вы пытаетесь расширить встроенный. Магия!--2--> методы не вызываются для builtins. Я думаю, вам придется сделать что-то вроде wrap-and-delegate, как это (непроверено) (возможно, Анураг опередил меня):

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 получить вызов подклассов 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
'***'

таким образом, определенно существует некоторая непоследовательность...