New Python 3.0 string formatting - really necessary?

MRAB google at mrabarnett.plus.com
Mon Dec 22 03:42:56 CET 2008


Aaron Brady wrote:
> On Dec 21, 6:14 pm, MRAB <goo... at mrabarnett.plus.com> wrote:
>> Aaron Brady wrote:
>>> On Dec 21, 10:58 am, MRAB <goo... at mrabarnett.plus.com> wrote:
>>>> Aaron Brady wrote:
>>>>> On Dec 21, 10:31 am, MRAB <goo... at mrabarnett.plus.com> wrote:
>>> snip
>>>>>> The original format is a string. The result of '%' is a string if
>>>>>> there's only 1 placeholder to fill, or a (partial) format object (class
>>>>>> "Format"?) if there's more than one. Similarly, the format object
>>>>>> supports '%'. The result of '%' is a string if there's only 1
>>>>>> placeholder to fill, or a new (partial) format object if there's more
>>>>>> than one.
>>>>>>  >>> f = "%r %i"
>>>>>>  >>> type(f)
>>>>>> <type 'str'>
>>>>>>  >>> f = f % (2, 3, 4)
>>>>>>  >>> type(f)
>>>>>> <type 'Format'>
>>>>>>  >>> f = f % 1
>>>>>>  >>> type(f)
>>>>>> <type 'str'>
>>>>> Alright, so how are you handling:
>>>>>>>> f= "%s %i"
>>>>>>>> type( f )
>>>>> <type 'str'>
>>>>>>>> f= f% '%i'  #now '%i %i'
>>>>>>>> type( f )
>>>>> <type 'Format'>
>>>>>>>> f= f% 1
>>>>>>>> type( f )
>>>>> ?
>>>>> In other words, are you slipping '1' in to the very first available
>>>>> slot, or the next, after the location of the prior?
>>>> Let's assume that Format objects display their value like the equivalent
>>>> string format:
>>>>  >>> f = "%r %i"
>>>>  >>> f
>>>> '%r %i'
>>>>  >>> f = f % (2, 3, 4)
>>>>  >>> f
>>>> <Format '(2, 3, 4) %i'>
>>>>  >>> f = f % 1
>>>>  >>> f
>>>> '(2, 3, 4) 1'
>>>>  >>> f = "%s %i"
>>>>  >>> f
>>>> '%s %i'
>>>>  >>> f = f % '%i'
>>>>  >>> f
>>>> <Format '%%i %i'>
>>>>  >>> f = f % 1
>>>>  >>> f
>>>> '%%i 1'
>>> I assume you meant '%i 1' since there are no more flags in f, and it's
>>> returned to a regular string.
>> Correct.
>>
>>> 'f %= 1' doesn't work any more as in-place modulo, since one time, 'f'
>>> is a Format object, the other, 'f' is a string.  Just raise an
>>> exception for that (or assign to __class__ IINM if I'm not mistaken).
>> All assignments rebind, even the augmented form:
>>
>>  >>> class C1(object):
>>         def __mod__(self, value):
>>                 return C2()
>>
>>  >>> class C2(object):
>>         def __mod__(self, value):
>>                 return C2()
>>
>>  >>> f = C1()
>>  >>> f
>> <__main__.C1 object at 0x00D144F0>
>>  >>> f % 0
>> <__main__.C2 object at 0x00D143F0>
>>  >>> f %= 0
>>  >>> f
>> <__main__.C2 object at 0x00D145B0>
>>
>>
>>
>>> Actually, the class you showed is kind of nifty.  Tuples are correctly
>>> interpolated.  I think on the whole you'll use more parenthesis, since
>>> each term in the tuple appears separately, and might be an expression
>>> (have a lower-precedence op.), as well as more modulo signs.
>>> You can currently do-it-yourself, you just need a constructor in the
>>> format string.
>>>>>> f = Format("%r %i")
>>>>>> type(f)
>>> <type 'Format'>
>>>>>> f = f % (2, 3, 4)
>>>>>> type(f)
>>> <type 'Format'>
>>> Or, as someone suggested earlier, a new literal marking:
>> Yes, I suggested that earlier, but it isn't needed because you can
>> create a format object with "Format(string)". However, most of the time
>> you won't bother to create a format object explicitly because of:
>>
>> class str(object):
>>      def __mod__(self, value):
>>          return Format(self) % value
>>
>>>>>> f = f"%r %i"
>>>>>> type(f)
>>> <type 'Format'>
>>  >>> # Explicitly
>>  >>> f = Format("%r %i")
>>  >>> f
>> <Format '%r %i'>
>>  >>> f % (2, 3, 4)
>> <Format '(2, 3, 4) %i'>
>>  >>>
>>  >>> # Implicitly, relying on the __mod__ method of str
>>  >>> f = "%r %i"
>>  >>> f
>> '%r %i'
>>  >>> f % (2, 3, 4)
>> <Format '(2, 3, 4) %i'>
>>
>> I'd also like to add that there's nothing to prevent format objects from
>> having other methods where multiple placeholders can be filled in one call:
>>
>>  >>> # By position
>>  >>> f = Format("%r %i")
>>  >>> f
>> <Format '%r %i'>
>>  >>> f.fill([(2, 3, 4), 1])
>> '(2, 3, 4) 1'
>>  >>>
>>  >>> # By name
>>  >>> f = Format("%{tuple}r %{int}i")
>>  >>> f
>> <Format '%{tuple}r %{int}i'>
>>  >>> f.fill({"tuple": (2, 3, 4), "int": 1})
>> '(2, 3, 4) 1'
> 
> You're choosing to favor the '.chain()' method over the '.fill()'
> method for the behavior of '%'.  I don't think you've justified it
> though.
> 
>>>> Format( "%r %i" ).chain( ( 2, 3, 4 ) ).chain( 0 )
> '(2, 3, 4) 0'
>>>> Format( "%r %i" ).fill( ( 2, 3, 4 ), 0 )
> '(2, 3, 4) 0'
> 
> Plus, I almost think we've almost attained defeating the purpose.
> 
The disadvantage of the chaining method is that it's positional, 
left-to-right. For the purposes of i18n you want tagged placeholders, 
whether they be integers or names. I think... OK, if the placeholders 
include a positional tag, eg "%(0)s %(1)s", then they could be filled in 
according to _that_ order. Not sure about named placeholders, though. 
Perhaps, like at present, if a dict is given to a format with named 
placeholders then several placeholders could be filled, the problem 
being how to fill a _single_ named placeholder with a dict.



More information about the Python-list mailing list