[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.python

Re: Making string-formatting smarter by handling generators?

Tim Chase

2/27/2008 8:42:00 PM

>> Is there an easy way to make string-formatting smart enough to
>> gracefully handle iterators/generators? E.g.
>>
>> transform = lambda s: s.upper()
>> pair = ('hello', 'world')
>> print "%s, %s" % pair # works
>> print "%s, %s" % map(transform, pair) # fails
>>
>> with a """
>> TypeError: not enough arguments for format string
>> """
>
> Note that your problem has nothing to do with map itself. String
> interpolation using % requires either many individual arguments, or a
> single *tuple* argument. A list is printed as itself.
>
> py> "%s, %s" % ['hello', 'world']
> Traceback (most recent call last):
> File "<stdin>", line 1, in <module>

I hadn't ever encountered this, as I've always used tuples
because that's what all the example code used. I thought it had
to do with indexability/iteration, rather than tuple'ness.
Apparently, my false assumption. People apparently use tuples
because that's the requirement, not just because it reads well or
is better/faster/smarter than list notation.

:)

> TypeError: not enough arguments for format string
> py> "%s" % ['hello', 'world']
> "['hello', 'world']"
>
> So the answer is always use tuple(...) as others pointed.

I'll adjust my thinking on the matter, and mentally deprecate
map() as well.

Thanks to all who responded.

-tkc



4 Answers

Steven D'Aprano

2/28/2008 1:18:00 AM

0

On Wed, 27 Feb 2008 14:41:32 -0600, Tim Chase wrote:

>>> Is there an easy way to make string-formatting smart enough to
>>> gracefully handle iterators/generators? E.g.
>>>
>>> transform = lambda s: s.upper()
>>> pair = ('hello', 'world')
>>> print "%s, %s" % pair # works
>>> print "%s, %s" % map(transform, pair) # fails
>>>
>>> with a """
>>> TypeError: not enough arguments for format string """

[snip]

I think there is a good case for % taking an iterator. Here's an
artificial example:

def spam():
while True: yield "spam"

spam = spam()

"%s eggs tomato and %s" % spam
"%s %s bacon tomato %s and eggs" % spam
"%s %s %s %s %s %s %s %s truffles and %s" % spam

The iterator could be arbitrarily complex, but the important feature is
that the % operator lazily demands values from it, taking only as few as
it needs. If the iterator is exhausted early, it is an error.


[...]


>> So the answer is always use tuple(...) as others pointed.
>
> I'll adjust my thinking on the matter, and mentally deprecate map() as
> well.

map() isn't deprecated, not even for Python 3 where it remains a built-
in. However it will return an iterator instead of a list, making it
(presumably) a more convenient way to spell itertools.imap().



--
Steven

Paul Rubin

2/28/2008 1:25:00 AM

0

Steven D'Aprano <steve@REMOVE-THIS-cybersource.com.au> writes:
> map() isn't deprecated, not even for Python 3 where it remains a built-
> in. However it will return an iterator instead of a list, making it
> (presumably) a more convenient way to spell itertools.imap().

That's the first I heard of that change. I guess it makes some
sense, however it is a bit weird, right now I use imap when I
want an iterator and use map when I explicitly want a list.

Maybe they can add something like "lmap" to return a list, as
an alternative to list(map( ... ))

Gabriel Genellina

2/28/2008 2:03:00 AM

0

En Wed, 27 Feb 2008 23:18:14 -0200, Steven D'Aprano
<steve@REMOVE-THIS-cybersource.com.au> escribió:

> I think there is a good case for % taking an iterator. Here's an
> artificial example:
>
> def spam():
> while True: yield "spam"
>
> spam = spam()
>
> "%s eggs tomato and %s" % spam
> "%s %s bacon tomato %s and eggs" % spam
> "%s %s %s %s %s %s %s %s truffles and %s" % spam
>
> The iterator could be arbitrarily complex, but the important feature is
> that the % operator lazily demands values from it, taking only as few as
> it needs. If the iterator is exhausted early, it is an error.

The % operator has to know whether you want to convert the iterator
itself, or the items yielded. Currently it checks whether its argument is
a tuple, and takes its contents. "%s" % "hello" is a (very handy) shortcut
for "%s" % ("hello",). Consider the following:

py> L = ["hello", "world"]
py> print "%s" % L
['hello', 'world']

Your suggestion would make it behave like this:

py> print "%s" % L
'hello'

Then, if one wants to display the container itself and not the contained
items, one should wrap *every* list and every sequence/iterator/iterable
object into an one-element tuple. Currently this is only required for
tuples.

Changing the % operator this way isn't a good idea, but your suggestion
could be used in another string method/operator/library function.

--
Gabriel Genellina

Steven D'Aprano

2/28/2008 2:43:00 AM

0

On Thu, 28 Feb 2008 00:03:02 -0200, Gabriel Genellina wrote:

> En Wed, 27 Feb 2008 23:18:14 -0200, Steven D'Aprano
> <steve@REMOVE-THIS-cybersource.com.au> escribió:
>
>> I think there is a good case for % taking an iterator. Here's an
>> artificial example:
>>
>> def spam():
>> while True: yield "spam"
>>
>> spam = spam()
>>
>> "%s eggs tomato and %s" % spam
>> "%s %s bacon tomato %s and eggs" % spam "%s %s %s %s %s %s %s %s
>> truffles and %s" % spam
>>
>> The iterator could be arbitrarily complex, but the important feature is
>> that the % operator lazily demands values from it, taking only as few
>> as it needs. If the iterator is exhausted early, it is an error.
>
> The % operator has to know whether you want to convert the iterator
> itself, or the items yielded. Currently it checks whether its argument
> is a tuple, and takes its contents. "%s" % "hello" is a (very handy)
> shortcut for "%s" % ("hello",).

You may not have noticed I said iterator, not iterable. I would expect
that general iterables like strings and lists would continue to work as
they do now.

[...]
> Changing the % operator this way isn't a good idea, but your suggestion
> could be used in another string method/operator/library function.

That's also a good option.


--
Steven