14

We have a list:

myList = [1, "two"]

And want to print it out, normally I would use something like:

"{0} and {1}".format(*myList)

But you could also do:

" and ".join(myList)

But unfortunately:

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

Why doesn't it just automatically convert the list it receives to strings?

When would you ever not need it to convert them to strings? Is there some tiny edge case I'm missing?

LittleBobbyTables
  • 4,361
  • 9
  • 38
  • 67

3 Answers3

14

From the Zen of Python:

Explicit is better than implicit.

and

Errors should never pass silently.

Converting to strings implicitly can easily hide bugs, and I'd really want to know if I suddenly have different types somewhere that were meant to be strings.

If you want to explicitly convert to strings, you can do so using map(), for example:

''.join(map(str, myList))
Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
  • 1
    Nice answer, but does "Explicit is better than implicit" really follow around all of python? .sorted() for example defaults to ascending, first element – LittleBobbyTables Mar 03 '14 at 17:04
  • 1
    @LittleBobbyTables: no, `list.sort()` defaults to using comparisons. It's up to the objects in the sequence what that means. For strings and tuples and lists, that's lexicographical, ascending. – Martijn Pieters Mar 03 '14 at 17:04
  • 1
    @LittleBobbyTables: And there are plenty of mistakes in Python 2 that have been corrected in Python 3. Implicit conversions between `str` and `unicode` for example. And a default ordering when sorting between disparate types cannot really be compared. – Martijn Pieters Mar 03 '14 at 17:06
  • 1
    @LittleBobbyTables: The Zen is a philosophy, a northern star to strive for. Yes, there are spots in the Python language that don't quite reach that, but `str.join()` does adhere to it. – Martijn Pieters Mar 03 '14 at 17:07
  • I think of this as "explicit > implicit" + "special cases aren't special enough to break the rules". In this *particular* case, converting to `str` wouldn't have been the worst thing ever, but keeping the number of implicit coercions to a minimum is also an important goal. (On practicality grounds you can pry 1 + 1.5 from me out of my cold, dead hands, but we needn't multiply such cases.) – DSM Mar 03 '14 at 17:09
  • @DSM: I actually considered quoting *special cases* here too but I didn't want to get into an argument how `str.join()` is not a special case - *sure it is* - no it's not, etc. – Martijn Pieters Mar 03 '14 at 17:13
3

The problem with attempting to execute something like x = 4 + "8" as written is that the intended meaning is ambiguous. Should x contain "48" (implicitly converting 4 to str) or 12 (implicitly converting "8" to int)? We can't justify either result.

To avoid this confusion, Python requires explicit conversion of one of the operands:

>>> x = str(4) + "8"
>>> y = 4 + int("8")
>>> print x
48
>>> print y
12
Tetrinity
  • 1,105
  • 8
  • 20
  • +1 for a practical justification for requiring explicit argument conversion. – chepner Mar 03 '14 at 17:56
  • 5
    Thanks for the answer but this is sort-of irrelevant as join() is about specifying a string to concatenate list items with, which doesn't leave this ambiguity. – LittleBobbyTables Mar 03 '14 at 19:02
  • It's still going to be attempting `1 + " and " + "two"` under the covers though, right? Using `mylist = [str(1), "two"]` allows the concatenation to work. – Tetrinity Mar 03 '14 at 19:09
  • 1
    This makes sense for the `+` operator, but `str.join` is a method of the `str` type and clearly isn't meant to operate on anything besides strings. So there is no confusion if you just convert everything to a string. – nog642 Feb 09 '21 at 05:16
0

Using the correct type is part of programming in Python. A general built-in like print does do the conversion (if the class supports __str__), which is where you should be doing it:

Let print do the work:

print(*myList, sep = " and ")

That's for Python 3, if you are still on Python 2 then use:

from __future__ import print_function
cdarke
  • 42,728
  • 8
  • 80
  • 84
  • Python is not strongly typed, it's not Java (thank god!). Join should be able to handle anything that with a __str__ method and use it. There's no ambiguity there. – OldGeeksGuide Feb 22 '22 at 17:44
  • Print is a function that prints stuff to a file or iostream, it doesn't generate a string, which is what I want if I'm using str.join. – OldGeeksGuide Feb 22 '22 at 17:46