[Python-ideas] textFromMap(seq , map=None , sep='' , ldelim='', rdelim='')

Masklinn masklinn at masklinn.net
Mon Oct 25 16:10:56 CEST 2010

On 2010-10-25, at 15:49 , spir wrote:
> Hello,
> A recommended idiom to construct a text from bits -- usually when the bits themselves are constructed by mapping on a sequence -- is to store the intermediate results and then only join() them all at once. Since I discovered this idiom I find myself constantly use it, to the point of having a func doing that in my python toolkit:
> def textFromMap(seq , map=None , sep='' , ldelim='',rdelim=''):
>    if (map is None):
>        return "%s%s%s" %(ldelim , sep.join(str(e) for e in seq) , rdelim)
>    else:
>        return "%s%s%s" %(ldelim , sep.join(str(map(e)) for e in seq) , rdelim)
> Example use:
> class LispList(list):
>    def __repr__(self):
>        return textFromMap(self , repr , ' ' , '(',')')
> print LispList([1, 2, 3])   # --> (1 2 3)
> Is there any similar routine in Python? If yes, please inform me off list and excuse the noise. Else, I wonder whether such a routine would be useful as builtin, precisely since it is a common and recommended idiom. The issues with not having it, according to me, are that the expression is somewhat complicated and, more importantly, hardly tells the reader what it means & does -- even when "unfolded" into 2 or more lines of code:
>    elements = (map(e) for e in seq)
>    elementTexts = (str(e) for e in elements)
>    content = sep.join(elementTexts)
>    text = "%s%s%s" %(ldelim , content , rdelim)
I really am not sure you gain so much over the current `sep.join(str(map(e)) for e in seq))`, even with the addition of ldelim and rdelim which end-up in arguments-soup/noise (5 arguments in the worst case is quite a lot).

The name is also strange, and hints at needing function composition more than a new builtin.

> 3. A method for iterables (1)   seq.textFromMap(...)
> (I personly find the latter more correct semantically (2).)
> (2) I think the same about join: should be "seq.join(sep)" since for me the object on which the method applies is seq, not sep.
This is also the choice of e.g. Ruby, but it has a severe limitation: Python doesn't have any `Iterable` type, yet `join` can be used with any iterable including generators or callable-iterators. Thus you can not put it on the iterable or sequence, or you have to prepare some kind of iterable mixin. This issue might be solved/solvable via the new abstract base classes, but I'm so sure about it (do you explicitly have to mix-in an abc to use its methods?).

In fact, Ruby 1.8 does have that limitation (though it's arguably not the worst limitation ever): `Array#join` exists but not `Enumerable#join`. They tried to add `Enumerable#join` in 1.9.1 (though a fairly strange, recursive version of it) then took it out then added it back again (or something, I got lost around there). And in any case since there is no requirement for enumerable collections to mix Enumerable in, you can have enumerable collections with no join support.

More information about the Python-ideas mailing list