Pythonのオブジェクトの継承関係

isinstance(object, classinfo) を使ってPythonの object について確認します。isinstance のドキュメントはこれです。

isinstance(object, classinfo)
object 引数が classinfo 引数のインスタンスであるか、 (直接、間接、または 仮想) サブクラスのインスタンスの場合に真を返します。 object が与えられた型のオブジェクトでない場合、この関数は常に偽を返します。 classinfo が型オブジェクトのタプル (あるいは再帰的に複数のタプル) の場合、 object がそれらのいずれかのインスタンスであれば真を返します。

Python 3.5.2です。

isinstanceの振舞いの確認

isinstance の動作を確認するために、自分で作った一般的なクラスについて確認します。

>>> class Spam:
...     ...
...
...
>>> spam = Spam()
>>> class Ham(Spam):
...     ...
...
...
>>> ham = Ham()
>>> isinstance(spam, Spam)
True
>>> isinstance(ham, Ham)
True
>>> isinstance(ham, Spam)
True
>>> isinstance(spam, Ham)
False
>>> isinstance(Spam, Spam)
False

Pythonのドキュメントの通り、インスタンスとそのインスタンスのクラスの組み合わせ、もしくはインスタンスとそのインスタンスのクラスの親クラスの組み合わせで True が返されています。

isinstanceのさらなる振舞い確認

Pythonのドキュメントの データモデルのオブジェクト、値、および型 にはこう記されています。

Python プログラムにおけるデータは全て、オブジェクトまたはオブジェクト間の関係として表されます。... 中略 ... 型自体もオブジェクトです

つまり os のようなモジュールも object ということになります。

>>> import os
>>> isinstance(os, object)
True

関数も object です。

>>> def egg():
...     ...
...
...
>>> isinstance(egg, object)
True

さきほど定義した Spam クラスや、そのインスタンスも object です。

>>> isinstance(Spam, object)
True
>>> isinstance(spam, object)
True

もちろん intstr のような基本的な型も object です。

>>> isinstance(int, object)
True
>>> isinstance(str, object)
True

ここで inspectisclass を確認すると、面白いことが分かります。コメントは除いてあります。

def isclass(object):
    return isinstance(object, type)

inspect.isclass(object) のドキュメントはこれです。

inspect.isclass(object)
オブジェクトが組み込みか Python が生成したクラスの場合に真を返します。

object という引数名のせいで少し分かりにくいですが、渡された値と typeisinstance を使って比較しています。 つまり、すべてのクラスは type のサブクラスのインスタンスであるということになります。

isinstance の第二引数に object を渡すことができていたことからも分かるように、 object はクラスです。そしてここまで確認してきたように、関数やモジュールも object のインスタンスでした。では type はどうでしょうか。

>>> isinstance(type, object)
True

typeobject のサブクラスのインスタンスでした。

面白いことに objecttype のサブクラスのインスタンスでもあります。

>>> isinstance(object, type)
True

では、 objecttype ではどちらが基底クラスになっているのでしょうか。ドキュメントからは object がすべての基底クラスであると読み取れますが、これを確認してみます。

>>> isinstance(egg, type)
False

さきほど使用した egg 関数は type のサブクラスのインスタンスではないことが確認できました。 ここまで確認したことを図にしました。

継承関係図

objectが基底にいる、ということは

これは余談ですが、自分で定義したクラスや、そのインスタンスに属性を持たせることはよくあることです。

>>> Spam.variable = 0
>>> Spam.variable
0
>>> spam.variable = 1
>>> spam.variable
1

Pythonでは object が関数の基底にいることを確認しました。

>>> egg.variable = 2
>>> egg.variable
2

なので、このように関数に属性を持たせることもできます。関数のドキュメントを __doc__ を参照することで得ることができますが、これも関数の属性にアクセスしていることになります。

>>> os.path.exists.__doc__
'Test whether a path exists.  Returns False for broken symbolic links'

コメント

2015 - 2017 (c) 成瀬基樹