Python であるオブジェクトが特定の型かどうかチェックするには isinstance 関数を使い、その時に「これは関数型か」「これはクラス型か」などのチェックを行うには types モジュールを使う。ただし、その時はちょっと注意が必要なので以下覚書。
まず Python は 2.2 だか 2.3 だったか忘れたが object 型が導入され、クラスの形式に二通りの表現方法が混在している(これは Python 3.0 では新形式に統一)。
# 旧式のクラス
class Foo():
pass
# 新しい書き方はこう(3.0 からはデフォルトで object を継承)
class Bar(object):
pass
両者の違いの詳細に付いてはドキュメント読めなんだが、その一つとして isinstance したときの挙動の違いがある。
>>> isinstance(Foo, types.ClassType)
True
>>> isinstance(Foo, types.TypeType)
False
>>> isinstance(Bar, types.ClassType)
False
>>> isinstance(Bar, types.TypeType)
True
一体なんでこんな事になってるのかと言うと、昔の Python ではクラスと型が未整理で、統一されているとは言い難かったということがある。例えば 1 という整数リテラルの型を調べてみると、それは int 型(types.IntType)となり、さらに int の型を調べてみると type 型(type.TypeType)となる。つまり、
という階層ができている。ところが旧式のクラスについてはこの階層から外れており、先の Foo クラスのインスタンス foo を作った場合、その型を type で調べた時の戻り値は instance となり、そこから型情報を得ることができない。型情報は __class__ 属性から取得できるが、これはちょっと不統一でわかりにくい。さっきと同じように箇条書きにすると、
という割と終わってる混沌状態であり、 2.x 系統の Python でとあるオブジェクトが組み込み型、ユーザ定義クラスを含めた型オブジェクトかどうか調べるには、旧式のクラスも考えた上で以下のように書く必要がある。
isinstance(o, types.ClassType) or isinstance(o, types.TypeType)
こういうのを見てるとさっさと Python 3.0 に移行したくなるけど、でもしばらくは 2.x 系統との共存が続くだろうからな。
この怪文書はクリエイティブ・コモンズ・ライセンスの元でライセンスされています。引用した文章など Kuwata Chikara に著作権のないものについては、それらの著作権保持者に帰属します。