337

In Python, I can do:

list = ['a', 'b', 'c']
', '.join(list)    # 'a, b, c'

However, if I have a list of objects and try to do the same thing:

class Obj:
    def __str__(self):
        return 'name'

list = [Obj(), Obj(), Obj()]
', '.join(list)

I get the following error:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: sequence item 0: expected string, instance found

Is there any easy way? Or do I have to resort to a for-loop?

5 Answers 5

496

You could use a list comprehension or a generator expression instead:

', '.join([str(x) for x in list])  # list comprehension
', '.join(str(x) for x in list)    # generator expression
Sign up to request clarification or add additional context in comments.

6 Comments

or a generator expression: ', '.join(str(x) for x in list)
any idea on which of them would be faster?
My experiments says that the list comprehension one can be a good 60% faster on small lists (experiment run 10^6 times on a list of three object()s). However, their performance is similar on big lists (2nd experiment run once on a 10^7 objects() list).
for a good 30% speed-up (over generator expression above), one can use the supposedly less readable map expression (below).
This answer is objectively worse than the map solution.
|
107

The built-in string constructor will automatically call obj.__str__:

''.join(map(str,list))

8 Comments

map() doesn't change the list, it's equivalent to [str(o) for o in list]
+1: Map is a good approach; "changing the list" isn't an accurate comment.
(another) +1.. map is not less readable, just need to know what the map function does
@Michael Not correct. reduce was the one that was removed, because it usually left people guessing and thus wasn't "pythonic". map on the other hand is not an issue.
(another) +1: coming from the Perl world this is the most common thing in the universe: join("sep", list) - and all elements of list get converted to their string representations. I've been really struggling to find a solution in python.
|
3

I know this is a super old post, but I think what is missed is overriding __repr__, so that __repr__ = __str__, which is the accepted answer of this question marked duplicate.

Comments

1

another solution is to override the join operator of the str class.

Let us define a new class my_string as follows

class my_string(str):
    def join(self, l):
        l_tmp = [str(x) for x in l]
        return super(my_string, self).join(l_tmp)

Then you can do

class Obj:
    def __str__(self):
        return 'name'

list = [Obj(), Obj(), Obj()]
comma = my_string(',')

print comma.join(list)

and you get

name,name,name

BTW, by using list as variable name you are redefining the list class (keyword) ! Preferably use another identifier name.

Hope you'll find my answer useful.

1 Comment

Never do that, defining your own classes for builtin types makes your code really hard to integrate
0

Not str.join but you can also use str.format to join the objects into a single string, especially if __str__ method is defined and lst is not very long.

class Obj:
    def __str__(self):
        return "name"

lst = [Obj(), Obj(), Obj()]
"{}, {}, {}".format(*lst)    # 'name, name, name'

If lst is very long and initializing specific number of placeholders is not feasible, then we can initialize a string of placeholders and format it afterwards (admittedly, very ugly though).

(len(lst)*"{}, ").format(*lst).rstrip(', ')

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.