11

I've already looked at this question on representing strings in Python but my question is slightly different. It is also different than the question How to concatenate (join) items in a list to a single string which was created after this question and applies to a list of strings and thus does not have any applicability to this question whatsoever (where the thrust of this question is specifically dealing with the challenge of non-string items).

Here's the code:

>>> class WeirdThing(object):
...     def __init__(self):
...         self.me = time.time()
...     def __str__(self):
...         return "%s" % self.me
...     def __repr__(self):
...         return ";%s;" % self.me
... 
>>> weird_list = [WeirdThing(), WeirdThing(), WeirdThing()]
>>> print weird_list
[;1302217717.89;, ;1302217717.89;, ;1302217717.89;]
>>> "\n".join(weird_list)
Traceback (most recent call last):
  File "<console>", line 1, in <module>
TypeError: sequence item 0: expected string, WeirdThing found

I realize that this works:

>>> "\n".join(str(wi) for wi in weird_list)
'1302217717.89\n1302217717.89\n1302217717.89'
>>> 

Still it would be nice to avoid doing that every time I want to join the objects together. Is it simply not possible?

Jordan Reiter
  • 20,467
  • 11
  • 95
  • 161

5 Answers5

13

You have to stringify your objects before you can join them. This is because str.join expects a series of strings, and you must give it a series of strings.

For the sake of less typing at the cost of readability, you can do "\n".join(map(str, list_of_things).

  • 1
    An alternative would be to use a generator expression: `'\n'.join((str(x) for x in list_of_things))` – Wesley Apr 08 '11 at 01:00
  • 1
    Thats what the OP had in his post, which, i believe, is the preferred way over using map. – dting Apr 08 '11 at 02:05
  • 1
    Thanks. I was hoping there was some way to make this implicit in the way that JavaScript automatically calls the .toString() method on an object when used as a string. Then of course I remembered: [Explicit is better than implicit.](http://www.python.org/dev/peps/pep-0020/) – Jordan Reiter Apr 08 '11 at 18:12
3

There are probably no amazing way.

def strjoin(glue, iterable):
    return glue.join(str(s) for s in iterable)
minhee
  • 5,688
  • 5
  • 43
  • 81
3

"...it would be nice to avoid doing that every time..."

You want to avoid repeating that same code multiple times? Then use a function;:

def join_as_str(alist):
    return "\n".join(str(item) for item in alist)
Duncan
  • 92,073
  • 11
  • 122
  • 156
1

Would it work for you if you added an __add__ method? E.g.,

from operator import add
from random import randint

class WeirdThing(object):
    def __init__(self,me=None):
        self.me = me if me else chr(randint(97,122))
    def __str__(self):
        return "%s" % self.me
    def __repr__(self):
        return ";%s;" % self.me
    def __add__(self,other):
        new_me = add(str(self.me),str(other.me))
        return WeirdThing(new_me)

weird_list = [WeirdThing(), WeirdThing(), WeirdThing()]
print weird_list

gives,

[;y;, ;v;, ;u;]

and this,

strange_thing = reduce(add,weird_list)
print strange_thing

gives,

yvu
lafras
  • 8,712
  • 4
  • 29
  • 28
  • `str.join()` has linear complexity, this is quadratic. For any length of list this is going to have horrible performance from all the temporary intermediate strings that are produced. – Duncan Apr 08 '11 at 08:14
0

You technically aren't joining the list of python objects, just their string representation.

>>> reduce(lambda x,y: "%s\n%s" % (x,y), weird_list)
'1302226564.83\n1302226564.83\n1302226564.83'
>>> 

This works as well but doesn't look any nicer:

>>> a = ""
>>> for x in weird_list:
...     a+="%s\n" % x
... 
>>> print a
1302226564.83
1302226564.83
1302226564.83

>>>
dting
  • 38,604
  • 10
  • 95
  • 114