objectとtypeの関係を図にまとめた
- object は継承の頂点
- type はインスタンス化の頂点
なお、図では以下のようなクラスを使いました。
# 何も継承指定しないとobjectを継承したことになる(※Python3から) class Foo: pass # Fooを継承 class Bar(Foo): pass # 独自のメタクラスを作成して使用 class MyType(type): pass class Hoge(metaclass=MyType): pass # クラスのインスタンス化 f = Foo() b = Bar() h = Hoge() # ビルトインタイプのインスタンス化 n = 123 s = 'hello'
object
クラスの継承元を辿っていくと必ずobjectにたどり着きます。
# 再掲 class Foo: pass class Bar(Foo): pass # ごく普通の継承 print(Foo.__bases__[0] is object) # True print(Bar.__bases__[0].__bases__[0] is object) # True !! # ビルトインタイプも同様 print(int.__bases__[0] is object) # True print(str.__bases__[0] is object) # True
なぜ __bases__[0]
のように複数形なのかというと、多重継承できるからです。
type
Pythonではクラスも含め全てがオブジェクトということになっています。では「そのオブジェクトはどのクラスから作られたの?」という質問を繰り返すと必ずtypeに辿り着きます。
# 再掲 n = 123 s = 'hello' f = Foo() b = Bar() h = Hoge() # あなたのクラスは...? print(n.__class__ is int) # True print(s.__class__ is str) # True print(f.__class__ is Foo) # True print(b.__class__ is Bar) # True print(h.__class__ is Hoge) # True # あなたのクラスのクラスは...? print(n.__class__.__class__ is type) # True print(s.__class__.__class__ is type) # True print(f.__class__.__class__ is type) # True print(b.__class__.__class__ is type) # True print(h.__class__.__class__ is MyType) # True !! print(h.__class__.__class__.__class__ is type) # True !!
issubclass / isinstance という関数もあるけれど
実は issubclass や isinstance 関数を使うと、継承関係を一発で調べることができます。
print(issubclass(Bar, Foo)) # True print(issubclass(Bar, object)) # True print(isinstance(b, Bar)) # True print(isinstance(b, Foo)) # True print(isinstance(Bar, type)) # True print(isinstance(Hoge, MyType)) #True !!
一方で、これらの関数は実際の継承関係になくても、継承していることにしてしまうことがあるので、この記事では使いませんでした。
from collections.abc import Sequence print(issubclass(str, Sequence)) # True !! print(isinstance('hello', Sequence)) # True !! # str は Sequence なんぞ継承しとらんぞ print(str.__mro__) # (<class 'str'>, <class 'object'>)
なぜこんな機能が必要かというと、↓このような型チェックのために使います。ダックタイピングってやつです。
import collections.abc # 何も継承しない(objectは除く) class ZZZ: def __len__(self): return 0 def print_length(obj): # 抽象基底クラスの確認 if isinstance(obj, collections.abc.Sized): print('あなたの長さは %d です' % len(obj)) else: print('あなたに長さはありません') # 長さのあるオブジェクト達 print_length('hello') # 5 print_length([1, 2, 3]) # 3 print_length({'A':'ei', 'B':'bee'}) # 2 print_length(ZZZ()) # 0 # 長さのないオブジェクト達 print_length(None) # なし print_length(open) # なし print_length(123) # なし
以上です。