Personally what I find is perverse is that .join is a method of strings
but does NOT call str() on the items to be joined. 

Yeah, that's a good reason to use .format when you have a fixed number of arguments.

"{}, {}, {}, {}".format(some, random, stuff, here)

And then there is map.

Otherwise .join is very common on iterables like 

'\n'.join(make_string(object) for object in something)

'\n'.join(map(make_string, something))

'\n'.join(map(str, nonstr))

'\n'.join('{}: {}'.format(x, y) for x,y in blabla)

'\n'.join(map('[{}]'.format, stuff))

A "join format" construct is very typical in codes producing strings from iterable.

I agree on the part "a list doesn't always contain string so why would it have a join method".