Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Custom string joining

123 views
Skip to first unread message

Claudiu Popa

unread,
May 7, 2011, 8:31:33 AM5/7/11
to pytho...@python.org
Hello Python-list,

I have an object which defines some methods. I want to join a list or
an iterable of those objects like this:

new_string = "|".join(iterable_of_custom_objects)

What is the __magic__ function that needs to be implemented for
this case to work? I though that __str__ is sufficient but it doesn't seems to
work. Thanks in advance.

PC

Chris Rebert

unread,
May 7, 2011, 10:25:58 AM5/7/11
to Claudiu Popa, pytho...@python.org

You need to do the string conversion yourself; .join() doesn't do it
for you, due to strong typing. It only accepts iterables of strings:
new_string = "|".join(str(x) for x in iterable_of_custom_objects)

Cheers,
Chris
--
http://rebertia.com

Martineau

unread,
May 9, 2011, 3:26:28 PM5/9/11
to

Instead of join() here's a function that does something similar to
what the string join() method does. The first argument can be a list
of any type of objects and the second separator argument can likewise
be any type. The result is list of the various objects. (The example
usage just uses a list of string objects and separator to illustrate
what it does.)

def tween(seq, sep):
return reduce(lambda r,v: r+[sep,v], seq[1:], seq[:1])

lst = ['a','b','c','d','e']

print tween(lst, '|')
print ''.join(tween(lst, '|'))

Output:

['a', '|', 'b', '|', 'c', '|', 'd', '|', 'e']
a|b|c|d|e


It could be made a little more memory efficient by applying the
itertools module's islice() generator to the first 'seq' argument
passed to reduce():

def tween(seq, sep):
return reduce(lambda r,v: r+[sep,v], itertools.islice(seq,1,None),
seq[:1])


--
Martin

Ian Kelly

unread,
May 9, 2011, 4:07:40 PM5/9/11
to Martineau, pytho...@python.org
On Mon, May 9, 2011 at 1:26 PM, Martineau <ggrp2.20....@dfgh.net> wrote:
> Instead of join() here's a function that does something similar to
> what the string join() method does. The first argument can be a list
> of any type of objects and the second separator argument can likewise
> be any type. The result is list of the various objects. (The example
> usage just uses a list of string objects  and separator to illustrate
> what it does.)
>
> def tween(seq, sep):
>    return reduce(lambda r,v: r+[sep,v], seq[1:], seq[:1])
>
> lst = ['a','b','c','d','e']
>
> print tween(lst, '|')
> print ''.join(tween(lst, '|'))
>
> Output:
>
> ['a', '|', 'b', '|', 'c', '|', 'd', '|', 'e']
> a|b|c|d|e
>
>
> It could be made a little more memory efficient by applying the
> itertools module's islice() generator to the first 'seq' argument
> passed to reduce():
>
> def tween(seq, sep):
>    return reduce(lambda r,v: r+[sep,v], itertools.islice(seq,1,None),
> seq[:1])


This version accepts any iterable, not just a list:

def tween(seq, sep):
it = iter(seq)
try:
first = it.next()
except StopIteration:
return []
return reduce(lambda r, v: r + [sep, v], it, [first])

A further efficiency improvement would be to do the list concatenation
in place to avoid generating O(n) intermediate copies:

def tween(seq, sep):
it = iter(seq)
try:
first = it.next()
except StopIteration:
return []
def add_sep(r, v):
r += [sep, v]
return r
return reduce(add_sep, it, [first])

Karim

unread,
May 9, 2011, 4:14:38 PM5/9/11
to Chris Rebert, Claudiu Popa, pytho...@python.org
On 05/07/11 16:25, Chris Rebert wrote:

> On Sat, May 7, 2011 at 5:31 AM, Claudiu Popa<cp...@bitdefender.com> wrote:
>> Hello Python-list,
>>
>> I have an object which defines some methods. I want to join a list or
>> an iterable of those objects like this:
>>
>> new_string = "|".join(iterable_of_custom_objects)
>>
>> What is the __magic__ function that needs to be implemented for
>> this case to work? I though that __str__ is sufficient but it doesn't seems to
>> work. Thanks in advance.
> You need to do the string conversion yourself; .join() doesn't do it
> for you, due to strong typing. It only accepts iterables of strings:
> new_string = "|".join(str(x) for x in iterable_of_custom_objects)

You just have to implement __str__() python special method for your
"custom_objects".

Regards
Karim

Claudiu Popa

unread,
May 9, 2011, 4:25:27 PM5/9/11
to pytho...@python.org
Hello Karim,


> You just have to implement __str__() python special method for your
> "custom_objects".

> Regards
> Karim
>> Cheers,
>> Chris
>> --
>> http://rebertia.com

I already told in the first post that I've implemented __str__ function, but it doesn't
seems to be automatically called.
For instance, the following example won't work:

>>> class a:
def __init__(self, i):
self.i = i
def __str__(self):
return "magic_function_{}".format(self.i)
>>> t = a(0)
>>> str(t)
'magic_function_0'
>>> "".join([t])
Traceback (most recent call last):
File "<pyshell#13>", line 1, in <module>
"".join([t])
TypeError: sequence item 0: expected str instance, a found

--
Best regards,
Claudiu

Martineau

unread,
May 9, 2011, 5:38:24 PM5/9/11
to

The built-in str join() method just doesn't do the conversion to
string automatically -- instead it assume it has been given a sequence
of string. You can achieve the effect you want by modifying the
optimized version of my earlier post that @Ian Kelly submitted.

def join(seq, sep):
it = iter(seq)
sep = str(sep)


try:
first = it.next()
except StopIteration:
return []
def add_sep(r, v):

r += [sep, str(v)]
return r
return ''.join(reduce(add_sep, it, [str(first)]))

class A:


def __init__(self, i):
self.i = i
def __str__(self):
return "magic_function_{}".format(self.i)

lst = [A(0),A(1),A('b'),A(3)]

print repr( join(lst, '|') )

Output:

'magic_function_0|magic_function_1|magic_function_b|magic_function_3'

Terry Reedy

unread,
May 9, 2011, 7:16:24 PM5/9/11
to pytho...@python.org
On 5/9/2011 4:25 PM, Claudiu Popa wrote:

> I already told in the first post that I've implemented __str__ function,
> but it doesn't seems to be automatically called.

No, Python does not auto-coerce to strings (only between numbers).
You have to be explicit by calling str. Karim's statement "You just have

to implement __str__() python special method for your "custom_objects".

" means that str will then work.

> For instance, the following example won't work:
>
>>>> class a:
> def __init__(self, i):
> self.i = i
> def __str__(self):
> return "magic_function_{}".format(self.i)
>>>> t = a(0)
>>>> str(t)
> 'magic_function_0'
>>>> "".join([t])

print('\n'.join(str(ob) for ob in [a(0), a(1), a(None)]))

magic_function_0
magic_function_1
magic_function_None

--
Terry Jan Reedy

Claudiu Popa

unread,
May 10, 2011, 1:51:55 AM5/10/11
to pytho...@python.org
Hello Terry,

Thanks, I understand now.

> magic_function_0
> magic_function_1
> magic_function_None


--
Best regards,
Claudiu

0 new messages