2014/12/10

【Python】 Class(3) (継承と) 新スタイルと旧スタイル

「言うまでもなく、継承の概念をサポートしない言語機能は “クラス” と呼ぶに値しません。」
Pythonチュートリアル 9.5. 継承 より
http://docs.python.jp/2.7/tutorial/classes.html#tut-inheritance

……というわけで、
前二回は継承に触れずにいたのですなわちクラスと呼ぶに値しないクラスの解説だったわけですが。

表題の通り、Pythonのクラスは新旧2種類に分けられます。
というのも現在Pythonは2系と3系のふたつのバージョンが並行しているためで、
新スタイルはいわば3系以降のためのクラス。
旧スタイルクラスは、3系では新スタイルに取って代わられます。


現在の2系のPython (20141209現在、2.7.8が最新)は、3系との橋渡しのために、
新スタイルも旧スタイルも使えるようになっています。
新スタイルクラスは、Python 2.2 で登場したそうです。

継承についてざっくり


新旧クラスについての前に、まず継承について。

class クラス名( 継承したい型/クラス ):
    〜〜クラスの内容

このように、クラス名の後に括弧書いて、その中に親クラスを書くと、親クラスの変数/関数を引き継いだクラスを作成していくことができます。
この“ワザを引き継ぐ”的なのを、『継承』と言います。これによって、すでにあるクラス、誰かが書いたクラスや元からある型に自分の欲しい機能を書き足したクラス、というのを作ることが出来ます。親クラスは複数記述できるので、いろいろ組み合わせて目的の機能を実現するといったことができます。

なにも継承しない場合は、括弧は省くことが出来ます。

class クラス名:
    〜〜クラスの内容

この場合、2系では「旧スタイルクラス」、3系では「新スタイルクラス」になります。
さて、
2系で新スタイルクラスと旧スタイルクラスは、このように書き分けます。


class OLD_style:
    pass

class NEW_style( object ):
    pass

このように、クラスを宣言するときに「(object) をつけるかどうか」(=objectを継承するかどうか)で新スタイルか旧スタイルかを選択します。
もしくは、他の新スタイルなクラスを継承するとかでも新スタイルに出来ます。

ちなみにドキュメントには
http://docs.python.jp/2/reference/datamodel.html#newstyle
「ユーザが好んで指定した場合のみ旧スタイルが使用されます。」
って書いてあるんですけど、そのやや下に「互換性のために、デフォルトではクラスは旧スタイルになります。」とも書いてあって、ん?ってなります。いや、デフォルトが旧スタイルなのは文句なしなんですが、そうすると「好んで指定した場合のみ」っていうのはアレレ的な的な。

新スタイルクラスは、「型」と「クラス」を統一するために用意されたそうです。
それまでは型を調べるための関数「type()」で問い合わせても「クラスだよ」「インスタンスだよ」とか返って来ていたのですが、新スタイルで作ったクラスだと、「型だよ」と返って来ます。

class OLD_style:
    pass

print type(OLD_style)    # -> <type classobj="">

oldTest = OLD_style()
print type(oldTest)    # -> <type instance="">


class NEW_style( object ):
    pass

print type(NEW_style)    # -> <type type="">

newTest = NEW_style()
print type(newTest)    # -> <class main__.new_style="">


object型

……ところで、新スタイルで継承している「object」って何でしょうか。
単純に

print object

してみると、

<type object="">

と出力されるので、なにやらデータ型であることは分かります。

dirしてみるとこんな感じ

print dir(object)
['__class__', '__delattr__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__']

なんかいっぱい入ってます。
これらが新スタイルクラスを新スタイルクラスたらしめていることになります。
ドキュメントによると、このようなことが。

http://docs.python.jp/2/glossary.html#term-object
https://docs.python.org/2.7/glossary.html#term-object

『状態と定義された振る舞いをもつ全てのデータ』

はあ、なんですかそれは。(原文では「Any data」……「任意のデータ」)
また、object のすぐ上の項目が「new-style class」なのであわせて確認してみると

  • objectを継承した全てのクラスは「新スタイルクラス」
  • 新スタイルクラスの究極の(※原文より)基底クラスが、object

……ってことなので、とりあえずのところ、
object型は新スタイルクラスのために存在し、新スタイルと旧スタイルのスイッチ、というあたりで手打ち。

「新」なところ


旧スタイルとはいろんなところが違うそうですが、重要なものに「特殊メソッド」が挙げられると思います。
旧スタイルから使える特殊メソッドもありますが、新スタイルでのそれらを駆使すると、
例えば「演算子のオーバーライド」が行なえたりします。
『演算子( + とか * とか)のオーバーライド(=上書き)』つまり、新スタイルクラス同士の足し算、引き算、かけ算...などなどをした時の振る舞いを自分で制御できたりするわけです。
pymel での「アトリビュートの接続(>>)、切断(//)」もこれによって実現されています。

こことか
https://github.com/LumaPictures/pymel/blob/master/pymel/core/general.py#L3141
こことか
https://github.com/LumaPictures/pymel/blob/master/pymel/core/general.py#L3153


特殊メソッドについてはこちらが詳しいんです。
http://diveintopython3-ja.rdy.jp/special-method-names.html

次回以降、こういったあたりをちょいちょいやって行けたらと思います。



■ 参考

9.5. 継承 @ Python チュートリアル
http://docs.python.jp/2/tutorial/classes.html?highlight=継承#tut-inheritance

新スタイルと旧スタイル @ Python 言語リファレンス
http://docs.python.jp/2/reference/datamodel.html#newstyle

new-style-class @ 用語集 Python 2.7ja1 documentation
http://docs.python.jp/2/glossary.html#term-new-style-class

新しい型を定義する」という節が
 Python インタプリタの拡張と埋め込み というドキュメントの中にもありますが、
こっちはCとか使っちゃうもっとハードなやつです。
http://docs.python.jp/2/extending/index.html

2 件のコメント:

  1. > 「ユーザが好んで指定した場合のみ旧スタイルが使用されます。」

    これ誤訳ギミですね。原文は "..., and old-style classes were the only flavor available." で「旧スタイルが唯一の書き方だった」ぐらいの意味です。

    返信削除
    返信
    1. やはりそうですよね。。。
      flavor が favor に見えたのかなというところまで想像しました(^^;;

      削除