String.join revisited (URGENT for 1.6)

Terry Reedy tjreedy at udel.edu
Tue May 30 15:48:20 EDT 2000


Unlike some others, I am comfortable enough with
joinstring.join(stringseq).  I see 'join' is a message to joinstring to
join up the items in stringseq (currently, a tuple or list) with itself and
return the result as one string.

One can argue that stringseq.join(joinstring), as a message to stringseq to
join its members with joinstring, is just as sensible.  (But then the
method should be 'joinwith' to read semigramatically).
True: ambiguity of where to direct messages is inherent in the
object-message paradigm (and to my mind, one of its disadvantages).

So, if we are going to choose (and the option not too is currently being
left in the string module), which is better?  I think the following
considerations point to the current choice of join as a string method.

0. Tuples currently do not have methods, so a full (rather than half)
implementation of the other choice is currently not possible!

1. Any string can be used as a joiner, but not all tuple/lists can be
joined (as join is currently implemented).  One input and the output are
strings, and the other input is a sequence of strings.  Join is about
strings, and not about general sequences (or even general tuples and
lists).

2. It is common to use one joinstring (such as ' ', ',' or ', ') to join
mupliple stringseqs and rare to join one stringseq with multiple
joinstrings.   (The same is true for realworl nails, staples, glue joining
batches of wood, cardboard, fabric, paper, etc.)   It is at least as
sensible to consider joining to be a method of the relatively stable (in
any particular context) joiner as to think of it as a method of the more
variable collection being joined.

3. Generalization seems more sensible this way.  For instance, suppose I
want to be able to join any sequence and have non-string items converted to
strings:

import string;  join = string.join

class joiner:
  def __init__(s, sep):
    # assert (type(sep) == type(''))
    s.sep = sep
  def join(s, seq):
    # return s.sep.join(map(str, seq))
    return join(map(str, seq), s.sep)  # don't have 1.6 yet

comma = joiner(', ')
comma.join((1,2,3))
# '1, 2, 3'
comma.join('string')
# 's, t, r, i, n, g'

(Yes, Python's easy flexibility continues to delight me.)

If one wrapped sequences in a joinseq class to give them a joinwith method,
one would usually have to create and delete a new instance with every
joining, instead of reusing one wrapped joiner, as above:

comma = ', '
joinseq((1,2,3)).joinwith(comma)
joinseq('string').joinwith(comma)

I personally prefer the joiner construction.

Terry J. Reedy







More information about the Python-list mailing list