No 1.6! (was Re: A REALLY COOL PYTHON FEATURE:)

Fredrik Lundh effbot at telia.com
Sat May 13 21:35:45 EDT 2000


François Pinard <pinard at iro.umontreal.ca> wrote:
>         TEXT.FUNCTION(ARG1, ARG2...)
>
> in 1.6.  That is, the _first_ argument in the functional writing becomes
> the object of the object-form writing.  The fact that we have:
>
>         string.join(SEQUENCE [, TEXT])
>
> with TEXT not being the first argument, and even optional, is the source of
> the bizarreness.  It shows to me that the `join' method is not really meant
> to be a string method, the string is just not the important object, here.
> The 1.6 writing does not look neat, and I would rather see `join' as a
> method of sequences, would it mean adding that method to all sequence types.

umm.  join works on everything that implements the abstract
sequence *protocol*.  there is no sequence "base class"...

> I would also much like that `TEXT' remains optional:
>
>         SEQUENCE.join()
>
> should return the string of sequence elements joined with spaces.

but now you're adding string-specific methods to *heterogeneous*
container objects...

> Maybe that part of the problem is that the meaning of the word `join' is
> ambiguous, and disambiguated by prefixing it by `string'.  The original
> problem might come from there: the prefixation is used in this case to
> "explain" the word `join', much more than to say which kind of object is
> mainly operated by the function.

well, since it doesn't belong in either of the classes, how about
turning it into a function?

    def join(sequence, sep=" "):
        out = ""
        if sequence:
            out = out + sequence[0]
            for item in sequence[1:]:
                out = out + sep + item
        return out

using this on long sequences is not very efficient, of course.  all
those concatenations will mean lots and lots of unnecessary re-
allocations and copying of substrings.

maybe we can optimize things a bit?  let's see...  how about:

    import strop, unistrop
    def join(sequence, sep=" "):
        if type(sequence[0]) is type(""):
            return strop.join(sequence, sep)
        if type(sequence[0]) is type(u""):
            return unistrop.join(sequence, sep)
        raise ValueError, "unknown string type"

hmm.  that doesn't work if the string is empty, of course.  maybe
we should use the type of the separator instead?

    import strop, unistrop
    def join(sequence, sep=" "):
        if type(sep) is type(""):
            return strop.join(sequence, sep)
        if type(sep) is type(u""):
            return unistrop.join(sequence, sep)
        raise ValueError, "unknown string type"

that's better.  just remember to add another if-clause if we're ever
adding another string type.

on the other hand, this design leaves us with two modules (strop
and unistrop), each containing a single function and nothing more.
maybe we can move the functionality into the actual string
implementation, through a hook method:

    def join(sequence, sep=" "):
        return sep.__join__(sequence)

much better.  it's obvious what type to use for the result, even
if the sequence is empty, and it's also very easy to extend with
new string-like objects.  and we don't need any extra modules.

on the other hand, using a "magic" name for this seems to be over-
kill.  how about just naming it "join", and let people call it directly if
they want?  TMTOWTDI, you know...

    def join(sequence, sep=" "):
        return sep.join(sequence)

much better than that non-intuitive 1.6 implementation.  now, all
that's left is to implement this.  let's start with the join function...

$ cd python-1.6\Lib
$ more string.py
...
def join(words, sep = ' '):
    return sep.join(words)
...

hmm.

</F>




More information about the Python-list mailing list