Pythonの型と二つのクラス、そしてインスタンス

Python Hack-a-thon 2011.02 のLTで使う資料を書いていてふと思い出したのが、Pythonでは厳密に言えば「クラスから生成したオブジェクト」を一言で表現する用語が無いのでめんどくさい、という話である。

C++などでは「インスタンス」と言ってしまえばお仕舞いなのだが、Pythonでは「インスタンス」には別の意味があるのでややこしい。クラス定義から作ったオブジェクトであっても、インスタンスだったりインスタンスじゃなかったりするのだ。

オブジェクトの「型」

まず、Pythonでの「型」について考えてみよう。Pythonでは、全てのオブジェクトは「型」を持っている。オブジェクトの「型」は type() で確認することができる。

>>> type(100)
<type 'int'>
>>> import sys
>>> type(sys)
<type 'module'>

数字はint、モジュールはmoduleという型のオブジェクトだ。「型」もまたオブジェクトであるので型を持っている。

>>> type(int)
<type 'type'>

全ての型は、type という型のオブジェクトなのである。

一つ目のクラス

Pythonの「クラス」とはなんだろうか?C++ではクラスは「ユーザ定義型」と呼ばれ、型の一種である。

Pythonでは、「クラス」は型だったり型ではなかったりする。Python2で、こんなクラス定義があったとする。

>>> class Spam:
...     pass
...

見てわかるとおり、Spamというクラスを定義している。さて、このSpamというのは何者だろうか?

>>> type(Spam)
<type 'classobj'>

Spamは、classobjという型のオブジェクトだ。つまり、Spamクラスはtype型ではないので、「型」ではないのである。

>>> isinstance(Spam, type)
False

インスタンス

ここで、Spamクラスからオブジェクトを生成しよう。

>>> spamobj = Spam()
>>> spamobj 
<__main__.Spam instance at 0x0283D3A0>
>>> type(spamobj )
<type 'instance'>

Spamクラスから、spamobjというオブジェクトを作った訳だが、Spamクラスは型ではないのでspamobjオブジェクトの型は当然「Spam」ではあり得ない。 クラスから生成されたオブジェクトは全て「instance」という型のオブジェクトとなるのである。

言い方を変えれば、インスタンスとはクラスから生成されたオブジェクト、ということになる。ん?だったら冒頭で

「クラスから生成したオブジェクト」を一言で表現する用語が無い

と書いたのはなんだんだ?

もう一つのクラス

さて、もう一つクラスを定義してみよう。

>>> class NewStyleSpam(object):
...     pass
...

今度は NewStyleSpam というクラスだ。Spamとの違いは、object型を継承している、という点のみだ。NewStyleSpamはどんなオブジェクトだろうか?

>>> type(NewStyleSpam)
<type 'type'>

先ほどのSpamクラスはclassobj型のオブジェクトだったが、NewStyleSpamクラスはtype型のオブジェクトだ。つまり、Spamクラスは型ではないが、NewStyleSpamクラスは型なのである。

つまり、NewStyleSpamのように、「型」を継承するクラスは、型となるのである。このように型から継承したクラスのことを、「新スタイルクラス(new style class)」と呼ぶ。

新スタイルクラスは「インスタンス」を生成しない

新スタイルクラスからオブジェクトを生成してみよう。

>>> newstylespamobj = NewStyleSpam()
>>> type(newstylespamobj)
<class '__main__.NewStyleSpam'>

Spamクラスから生成したオブジェクトは、instance型のオブジェクトであった。しかし、NewStyleSpamは型であるので、ここで生成したオブジェクトはNewStyleSpam型のオブジェクトである。Spamクラスはインスタンスを生成するが、NewStyleSpamが生成するのはNewStyleSpam型のオブジェクトであり、「インスタンス」型ではないのである。

通常はクラスから生成したオブジェクトを「インスタンス」と呼んでしまって問題ないのだが、厳密には新スタイルクラスは「インスタンス」を生成しない。実装上の細かい話をしている時には、この違いを意識してないと「?」となってしまうことがあるので、一応覚えておくと良いだろう。

Python3では

実は、ここまではPython2までの話だ。Python3では、Python2の「旧スタイルクラス」が存在せず、全て「新スタイルクラス」となる。

>>> class Spam:
...     pass
...
>>> Spam
<class '__main__.Spam'>
>>> type(Spam)
<class 'type'>
>>> type(Spam())
<class '__main__.Spam'>

classobj型やinstance型というのは使われていない。従って、Python3の世界は、クラスから生成したオブジェクトを「インスタンス」と言ってもなんら問題のないパラダイスなのである。