「(ruby|javascript)でstr.join(array)、pythonでlist.join(str)」http://blog.livedoor.jp/dankogai/archives/51226075.html
ここではlistを継承したListクラスをこさえて、そこにjoinメソッドを追加しているが、listに直にメソッド追加する方法はないのだろうか....
多分できない。
PythonはPerl,Rubyに比べて、上の方は同じくらい柔らかいんだけど、下の方は堅い。
Unicodeのことまで考慮に入れて実装したために、実装がずいぶんと泥臭いものになっている。
join したいものが一種類ではないというのが、 join が list のメソッドでない理由の一つだからね。
str()はUnicodeを食うと例外をお吐きになる。それでいて"dankogai" + u"小飼弾"はu"dankogai小飼弾"になってくれる。し、"+".join("dankogai" + u"小飼弾")も問題なくu"dankogai小飼弾"になってくれる。
ここは、Python初心者に取っては罠だ。(なのでpy3kではstrが撤去される)
str と unicode の関係は、例えば int と double のように、unicode 側に自動で格上げされるというものだ。なので u"foo" + "bar" の結果は u"foobar" になる。
格上げの際、str型にはascii文字列が入っているものとみなされ、ascii*1としてデコードできない場合はUnicodeDeocdeErrorが発生する。
逆に、str(u"foo") のように明示的に格下げする際も、ascii 以外の文字が入っていたら UnicodeEncodeError が発生する。
このことを理解すれば、合理的で一貫性が保たれているのが判るので、「それでいて」なんて思わなくなる。
さて、RubyのArray.join 相当の、勝手に中身を文字列に変換するjoinが欲しい場合、
def join(iterable, sep=''): return sep.join(unicode(x) for x in iterable)
で普通は充分だろう。やだやだ!unicodeが混じってない場合はstrじゃないとやだ!という場合は、
def join(iterable, sep=''): def s(x): if isinstance(x, basestring): return x return str(x) return sep.join(s(x) for x in iterable)
になるかな。文字列を += で繋げていくのは、文字列の長さに比例したコピーコストが発生して計算量が最悪 O(n^2) になる可能性があるのでお勧めできない。
というわけで、この件に関しては、「どちらがキモい」ではなく、「どちらが歩み寄りやすいか」という点においてPythonが見劣りするのは否めない。
他の言語に対しての「歩みより」は、Pythonが重視している価値ではないからね。
ブロック構文があればRubyistを取りこめるかもしれないけど、Pythonでは内包表記とwith文があるからブロック構文の必要性は皆無で、必要が無い機能は導入しない。
配列の中味をデリミタでjoin()する
にしても、
join the array elements with the delimiter
にしても、言葉に近いのは Ruby や JavaScript の方ではないか。
僕は主語の入れ替えができるという話をしたのに、通じなかったらしい。「紙をのりでくっつける」を「のりが紙をくっつける」と言い換えることが出きるみたいに、何を主語にするべきかなんてのは主観でしかないのに。
関数としてはjoin(delim, list)が、メソッドとしてはarray.join(delim)が落としどころのように感じられるのだが....
そんなに str.join が嫌なら import string; string.join() をどうぞ。
sep.join() が直感に反しているように思える人がいくら多くても、複数の文字列と複数のiterableを正しく扱うには、 str.join は合理的でも array.join は合理的ではない。