新スタイルのクラスと旧スタイルのクラス
【 目次 】
実はpython2ではクラスの記述方法により新スタイルと旧スタイルの2種類が存在し、それぞれのスタイルによりふるまいが異なり話しがややこしくなる。
python3の場合は旧スタイルのクラスは廃止されて、新スタイルのクラスのみが存在する。
何も継承しないクラスを記述する場合に以下のように記述する。
class MyCls(): クラスの内容を記述。
またクラス名の後のカッコを省略して以下のように記述する事もできる。
class MyCls: クラスの内容を記述。
そして、ややこしい事に上記の定義の他に
新スタイルのすべてのクラスの基底クラスとなるobjectクラスがあり、
以下のようなobjectクラスを継承したクラスは新スタイルのクラスと呼ばれる。
class NewStyleClass(object): クラスの内容を記述。
新スタイルのクラスに対して、何も継承しないクラスや何も継承しないクラスを基底クラスとするクラス(というか、何かわからないが無名のデフォルトの基底クラスを継承したクラス)の事を旧スタイルのクラスと呼ぶ。
新スタイルと旧スタイルの区別があるのはPython2系での話しであって、
Python3系では、旧スタイルのクラスが廃止され,上記のクラスの記述例はすべてobjectクラスを基底クラスとする新スタイルのクラスとして扱われる。
つまり、Python3では何も継承しないクラスはobjectクラスを継承したクラスとして扱われる。
新スタイルのクラスは型
クラスが旧スタイルか新スタイルかを判別するにはtype関数の結果をみるとわかるようだ。
旧スタイルの場合
class MyCls: pass my_inst=MyCls() print type(my_inst) print type(MyCls)
実行結果
<type 'instance'> <type 'classobj'>
新スタイルの場合
class MyCls(object): pass my_inst=MyCls() print type(my_inst) print type(MyCls)
実行結果
<class '__main__.MyCls'> <type 'type'>
つまり、type関数の引数に
旧スタイルのクラスを指定すると<type 'classobj'>
,
インスタンスを指定すると<type 'instance'>
と出力されるのに対して、
新スタイルのクラスを指定すると<type 'type'>
,
インスタンスを指定すると<class 'モジュール.クラス名'>
と出力される。
旧スタイルのクラスを継承したクラスは当然・旧スタイルのクラスに、
新スタイルのクラスを継承したクラスは新スタイルのクラスになるようだ。
実際にtype関数を利用して確認してみよう。
旧スタイルのクラスを継承したクラス
class MyCls: pass class MyClsEx(MyCls): pass my_inst_ex=MyClsEx() print type(MyClsEx) print type(my_inst_ex)
実行結果
<type 'classobj'> <type 'instance'>
旧スタイルのクラスを継承したクラス
class MyCls(object): pass class MyClsEx(MyCls): pass my_inst_ex=MyClsEx() print type(MyClsEx) print type(my_inst_ex)
実行結果
<type 'type'> <class '__main__.MyClsEx'>
スーパクラスが新スタイルか旧スタイルかによって、継承したクラスはスーパクラスと同じスタイルのクラスになる事が確認できる。
組込み型は新スタイルのクラス
ちなみにtype関数の引数に組込み型を指定してみると文字列型の場合、
s=str("abc") print s,type(s),type(str)
実行結果
abc <type 'str'> <type 'type'>
type関数の結果は新スタイルのクラスと同様となる事が確認できる。
__bases__属性を使って文字列型の基底クラスをたどってみる
print str.__bases__
実行結果
(<type 'basestring'>,)
文字列型の基底クラスはbasestring型で、
print basestring.__bases__
実行結果
(<type 'object'>,)
更に、basestringの基底クラスとしてobject型にたどりつく事になる。
これらの結果から、文字列型strに代表される組込み型は新スタイルのクラスという事になる。
つまり新スタイルのクラスは組込み型と同等のユーザ定義の型という扱いになる。
ちなみに、組込み型と同等のユーザ定義の型という事で、
組込み型を継承したユーザ定義の型をつくることもできる。
class MyString(str): def showMe(self): print self my_str=MyString("hello") my_str.showMe()
実行結果
hello
上述のとおり新スタイルのクラスの場合、
型とはクラス,クラスとは型と考えても良い。
ユーザ定義の新スタイルのクラスはユーザ定義の型として扱われるという事のようだ。
旧スタイルクラスと新スタイルクラスを多重継承すると新スタイルクラスのクラスになる?
旧スタイルクラスと新スタイルクラスを多重継承した場合どちらのクラスになるのだろう?
テストコードを記述して確認してみた。
class OldStyleCls: pass class NewStyleCls(object): pass class MyCls(OldStyleCls,NewStyleCls): pass my_inst=MyCls() print type(my_inst), type(MyCls)
実行結果
<class '__main__.MyCls'> <type 'type'>
旧スタイルクラスと新スタイルクラスの多重継承はできない、とてっきっりこのコードはエラーになるだろうと予測したのだが、
旧スタイルクラスと新スタイルクラスを多重継承した場合はどうやら新スタイルクラスになるようだ。
多分、superクラスをたどってどれか1つがobjectを継承していればobjectクラスの特性(新スタイルクラス)を持つ事ができるという事なのだろう。
旧スタイルと新スタイルの違い
旧スタイルと新スタイルにはどのような違いがあるのだろう。
-
とりあえず: [Python][お勉強] Python入門(59) - 新スタイルクラス
新スタイルクラスとクラシッククラスの違い
●オブジェクトツリーの検索順が違う
●新スタイルクラスではスタティックメソッド、クラスメソッドが使用できる
●新スタイルクラスでは__slots__属性が使用できる。
●新スタイルクラスでは「プロパティ」を使用することができる。
●新スタイルクラスでは__getattribute__メソッドを使用することができる。 - 14. Pythonの新スタイルクラス - Kura IT Lab
プロパティのもとになっているディスクリプタも新スタイルクラスのみで使えるようだ。
- プロパティについては「オブジェクトの属性を操る(3) - property(プロパティ)を参照
- ディスクリプタについては「オブジェクトの属性を操る(4) - ディスクリプタ」を参照
- スタティックメソッド、クラスメソッドについては「メソッドオブジェクト(1)」を参照
- __getattribute__メソッドについては「オブジェクトの属性を操る(2) - 属性へのアクセスをフックする}を参照
- __slots__属性については「クラスの特殊属性を活用してクラスのふるまいをカスタマイズする}を参照
新スタイルのクラスは、
- The History of Python.jp: 新スタイルクラス
しっかりと時間をとって「正しく動作する」ようにクラスの再実装を行った。
であるので、あえて旧スタイルのクラスを使う必要は無い。
本サイトでは、クラスと言えば基本的に新スタイルのクラスを意味している。