Pythonの文字列連結(join)にまつわる議論 まとめと考察(2)
だいぶ時間が開いてしまったけれど、Pythonの文字列joinの不思議について、さらに突っ込んだ解釈を試みてみましょう。
あくまでBetaNews的な解釈だけれど、
というのは、元々は次の形をしていると考えるべきなんじゃないか、っていうこと。
", ".join([...])
この解釈に基づいて、セパレータを省略すると、次の書き方が初期に存在したのではないか、と推測できる。
str(", ").join([...])
"".join([...])
この解釈が、BetaNews的な理解の第1段階なのだ。ここでは、strクラスを例に出したが、次のように定義されたクラスを導出してみよう。
そして、このクラスでのjoinは、
class Joiner(object):
@classmethod
def join(classObj, iterativeSequence):
tmpInstance = classObj()
#[Ommit]concat loop.
return tmpInstance
のように表現できる。だいぶ近づいてきた。では、導出したJoinerクラスをさらに拡張してみよう。
Joiner.join([...])
これが、セパレータとして機能するJoinerクラスの骨格だ。実際に使うとすれば、
class Joiner(object):
rawStr = False
def __init__(self, rawString):
if isinstance(rawString, basestring):
self.rawStr = rawString)
def join(self, iterativeSequence):
return reduce(lambda x, y:x + self.rawStr + y, iterativeSequence)
のようになります。Joinerクラスをそのままstrクラスと読み替えれば、現状のPythonの実装におけるjoin()メソッドの実装の説明として十分ではないかと思います。
Joiner(", ").join([...])
とはいえ、解釈を深めただけでは底が浅いな、と思われるので、ひとつ、joinメソッドがイテレーション オブジェクトをシリアライズするクラスに属していることによる多態性の応用例を挙げてみましょう。
単純なXML文書をシーケンスから得るクラスを定義してみた。軽くIDLEから使ってみると、次のようになります。
import xml.dom.minidom as DOM
class hoge(object):
@staticmethod
def join(iterativeInstance, parentName="items", childNode="item"):
tmpXmlDoc = DOM.parseString("""""")
parentNode = tmpXmlDoc.createElement(parentName)
if isinstance(iterativeInstance, dict):
for key in iterativeInstance.keys():
currChildNode = tmpXmlDoc.createElement(childNode)
currChildNode.setAttribute(str(key), iterativeInstance[key])
parentNode.appendChild(currChildNode)
else:
for value in iterativeInstance:
currChildNode = tmpXmlDoc.createElement(childNode)
if isinstance(value, basestring):
tmpTextElement = tmpXmlDoc.createTextNode(value)
else:
try:
tmpTextElement = tmpXmlDoc.createTextNode(str(value))
except:
tmpTextElement = tmpXmlDoc.createTextNode(repr(value))
currChildNode.appendChild(tmpTextElement)
parentNode.appendChild(currChildNode)
if parentNode.childNodes>0:
tmpXmlDoc.firstChild.appendChild(parentNode)
return tmpXmlDoc
strクラスのセパレータを使ったjoinメソッドと、まったく使い方のお作法が違わないにも関わらず、得られるインスタンスがきちんとminidomによるXML文書になっていることが分かります。Pythonにおけるjoinメソッドは、「シーケンスを“何か別のオブジェクト”にシリアライズする静的メソッドである」という解釈が、一番分かりやすく、かつオブジェクト指向における多態性(ポリモーフィズム)の考え方にも則していると思うのです。JavaScriptやRubyといった、シーケンスを“文字列型に固定で”シリアライズするメソッドとしてjoinメソッドを扱うよりも、実装としてこなれている感じがするのはBetaNewsだけでしょうか。
>>> d1 = hoge.join(["a", "b", "c"])
>>> print d1.toprettyxml()
a
b
c
>>> d2 = hoge.join({"foo1":"bar1", "foo2":"bar2"})
>>> print d2.toprettyxml()