新スタイルのクラスと旧スタイルのクラス

【 目次 】

実は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クラスの特性(新スタイルクラス)を持つ事ができるという事なのだろう。

旧スタイルと新スタイルの違い

旧スタイルと新スタイルにはどのような違いがあるのだろう。

プロパティのもとになっているディスクリプタも新スタイルクラスのみで使えるようだ。

新スタイルのクラスは、

であるので、あえて旧スタイルのクラスを使う必要は無い。
本サイトでは、クラスと言えば基本的に新スタイルのクラスを意味している。

ページのトップへ戻る