9. クラス
*********

クラスはデータと機能を組み合わせる方法を提供します。 新規にクラスを作
成することで、新しいオブジェクトの *型* を作成し、その型を持つ新しい *
インスタンス* が作れます。 クラスのそれぞれのインスタンスは自身の状態
を保持する属性を持てます。 クラスのインスタンスは、その状態を変更する
ための (そのクラスが定義する) メソッドも持てます。

Python は、他のプログラミング言語と比較して、最小限の構文と意味付けを
使ってクラスを言語に追加しています。Python のクラスは、C++ と Modula-3
のクラスメカニズムを混ぜたものです。Python のクラス機構はオブジェクト
指向プログラミングの標準的な機能を全て提供しています。クラスの継承メカ
ニズムは、複数の基底クラスを持つことができ、派生クラスで基底クラスの任
意のメソッドをオーバライドすることができます。メソッドでは、基底クラス
のメソッドを同じ名前で呼び出すことができます。オブジェクトには任意の種
類と数のデータを格納することができます。モジュールと同じく、クラス機構
も Python の動的な性質に従うように設計されています。クラスは実行時に生
成され、生成後に変更することができます。

C++ の用語で言えば、通常のクラスメンバ (データメンバも含む) は (プライ
ベート変数 に書かれている例外を除いて) *public* であり、メンバ関数はす
べて *仮想関数(virtual)* です。 Modula-3 にあるような、オブジェクトの
メンバをメソッドから参照するための短縮した記法は使えません: メソッド関
数の宣言では、オブジェクト自体を表す第一引数を明示しなければなりません
。第一引数のオブジェクトはメソッド呼び出しの際に暗黙の引数として渡され
ます。 Smalltalk に似て、クラスはそれ自体がオブジェクトです。そのため
、 import や名前変更といった操作が可能です。 C++ や Modula-3 と違って
、ユーザーは組込み型を基底クラスにして拡張を行えます。また、C++ とは同
じで Modula-3 とは違う点として、特別な構文を伴うほとんどの組み込み演算
子 (算術演算子 (arithmetic operator) や添字表記) はクラスインスタンス
で使うために再定義できます。

(クラスに関して普遍的な用語定義がないので、 Smalltalk と C++ の用語を
場合に応じて使っていくことにします。 C++ よりも Modula-3 の方がオブジ
ェクト指向の意味論が Python に近いので、 Modula-3 の用語を使いたいので
すが、ほとんどの読者は Modula-3 についてしらないでしょうから。)


9.1. 名前とオブジェクトについて
===============================

オブジェクトには個体性があり、同一のオブジェクトに(複数のスコープから)
複数の名前を割り当てることができます。この機能は他の言語では別名づけ
(alias) として知られています。 Python を一見しただけでは、別名づけの重
要性は分からないことが多く、変更不能な基本型 (数値、文字列、タプル)を
扱うときには無視して差し支えありません。しかしながら、別名付けは、リス
トや辞書や他の多くの型など、変更可能な型を扱う Python コード上で驚くべ
き効果があります。別名付けはいくつかの点でポインタのように振舞い、この
ことは通常はプログラムに利するように使われます。例えば、オブジェクトの
受け渡しは、実装上はポインタが渡されるだけなのでコストの低い操作になり
ます。また、関数があるオブジェクトを引数として渡されたとき、関数の呼び
出し側からオブジェクトに対する変更を見ることができます --- これにより
、 Pascal にあるような二つの引数渡し機構をもつ必要をなくしています。


9.2. Python のスコープと名前空間
================================

クラスを紹介する前に、Python のスコープのルールについてあることを話し
ておかなければなりません。クラス定義は巧みなトリックを名前空間に施すの
で、何が起こっているのかを完全に理解するには、スコープと名前空間がどの
ように動作するかを理解する必要があります。ちなみに、この問題に関する知
識は全ての Python プログラマにとって有用です。

まず定義から始めましょう。

*名前空間 (namespace)* とは、名前からオブジェクトへの対応付け
(mapping) です。ほとんどの名前空間は、現状では Python の辞書として実装
されていますが、そのことは通常は (パフォーマンス以外では) 目立つことは
ないし、将来は変更されるかもしれません。名前空間の例には、組込み名の集
合 ("abs()" 等の関数や組込み例外名)、モジュール内のグローバルな名前、
関数を呼び出したときのローカルな名前があります。オブジェクトの属性から
なる集合もまた、ある意味では名前空間です。名前空間について知っておくべ
き重要なことは、異なった名前空間にある名前の間には全く関係がないという
ことです。例えば、二つの別々のモジュールの両方で関数 "maximize" という
関数を定義することができ、定義自体は混同されることはありません --- モ
ジュールのユーザは名前の前にモジュール名をつけなければなりません。

ところで、 *属性* という言葉は、ドットに続く名前すべてに対して使ってい
ます --- 例えば式 "z.real" で、 "real" はオブジェクト "z" の属性です。
厳密にいえば、モジュール内の名前に対する参照は属性の参照です。式
"modname.funcname" では、 "modname" はあるモジュールオブジェクトで、
"funcname" はその属性です。この場合には、モジュールの属性とモジュール
の中で定義されているグローバル名の間には、直接的な対応付けがされます。
これらの名前は同じ名前空間を共有しているのです！ [1]

属性は読取り専用にも、書込み可能にもできます。書込み可能であれば、属性
に代入することができます。モジュール属性は書込み可能で、
"modname.the_answer = 42" と書くことができます。書込み可能な属性は、
"del" 文で削除することもできます。例えば、 "del modname.the_answer" は
、 "modname" で指定されたオブジェクトから属性 "the_answer" を除去しま
す。

名前空間は様々な時点で作成され、その寿命も様々です。組み込みの名前が入
った名前空間は Python インタプリタが起動するときに作成され、決して削除
されることはありません。モジュールのグローバルな名前空間は、モジュール
定義が読み込まれたときに作成されます。通常、モジュールの名前空間は、イ
ンタプリタが終了するまで残ります。インタプリタのトップレベルで実行され
た文は、スクリプトファイルから読み出されたものでも対話的に読み出された
ものでも、 "__main__" という名前のモジュールの一部分であるとみなされる
ので、独自の名前空間を持つことになります。 (組み込みの名前は実際にはモ
ジュール内に存在します。そのモジュールは "builtins" と呼ばれています。
)

関数のローカルな名前空間は、関数が呼び出されたときに作成され、関数から
戻ったときや、関数内で例外が送出され、かつ関数内で処理されなかった場合
に削除されます。 (実際には、忘れられる、と言ったほうが起きていることを
よく表しています。) もちろん、再帰呼出しのときには、各々の呼び出しで各
自のローカルな名前空間があります。

*スコープ (scope)* とは、ある名前空間が直接アクセスできるような、
Python プログラムのテキスト上の領域です。 "直接アクセス可能" とは、修
飾なしに (訳注: "spam.egg" ではなく単に "egg" のように) 名前を参照した
際に、その名前空間から名前を見つけようと試みることを意味します。

スコープは静的に決定されますが、動的に使用されます。実行中はいつでも、
直接名前空間にアクセス可能な、3つまたは4つの入れ子になったスコープがあ
ります:

* 最初に探される、最も内側のスコープは、ローカルな名前を持っています。

* 外側の(enclosing)関数のスコープは、近いほうから順に探され、ローカル
  でもグローバルでもない名前を持っています。

* 次のスコープは、現在のモジュールのグローバルな名前を持っています。

* 一番外側の(最後に検索される)スコープはビルトイン名を持っています。

名前が global と宣言されている場合、その名前に対する参照や代入は全て、
モジュールのグローバルな名前の入った最後から2番目のスコープに対して直
接行われます。最内スコープの外側にある変数に再束縛するには、
"nonlocal" 文が使えます。nonlocal と宣言されなかった変数は、全て読み出
し専用となります (そのような変数に対する書き込みは、単に *新しい* ロー
カル変数をもっとも内側のスコープで作成し、外部のスコープの値は変化しま
せん)。

通常、ローカルスコープは (プログラムテキスト上の) 現在の関数のローカル
な名前を参照します。関数の外側では、ローカルスコープはグローバルな名前
空間と同じ名前空間、モジュールの名前空間を参照します。クラス定義では、
ローカルスコープの中にもう一つ名前空間が置かれます。

スコープはテキスト上で決定されていると理解することが重要です。モジュー
ル内で定義される関数のグローバルなスコープは、関数がどこから呼び出され
ても、どんな別名をつけて呼び出されても、そのモジュールの名前空間になり
ます。反対に、実際の名前の検索は実行時に動的に行われます --- とはいえ
、言語の定義は、"コンパイル" 時の静的な名前解決の方向に進化しているの
で、動的な名前解決に頼ってはいけません！ (事実、ローカルな変数は既に静
的に決定されています。)

Python の特徴として、"global" や "nonlocal" 文が有効でない場合は、名前
に対する参照は常に最も内側のスコープに対して有効になります。 代入はデ
ータをコピーしません。オブジェクトを名前に束縛するだけです。削除も同様
で、"del x" は、ローカルスコープの名前空間から  "x" に対する拘束を取り
除きます。 つまるところ、新しい名前を与えるようなすべての操作は、ロー
カルスコープを使って行われます。 "import" 文、関数の定義は、モジュール
や関数名をローカルスコープの名前に拘束します。

"global" 文を使うと、特定の変数がグローバルスコープに存在し、そこで再
束縛されることを指示できます。 "nonlocal" 文は、特定の変数が外側のスコ
ープに存在し、そこで再束縛されることを指示します。


9.2.1. スコープと名前空間の例
-----------------------------

異なるスコープと名前空間がどのように参照されるか、また "global" および
"nonlocal" が変数の束縛にどう影響するか、この例で実演します:

   def scope_test():
       def do_local():
           spam = "local spam"

       def do_nonlocal():
           nonlocal spam
           spam = "nonlocal spam"

       def do_global():
           global spam
           spam = "global spam"

       spam = "test spam"
       do_local()
       print("After local assignment:", spam)
       do_nonlocal()
       print("After nonlocal assignment:", spam)
       do_global()
       print("After global assignment:", spam)

   scope_test()
   print("In global scope:", spam)

このコード例の出力は:

   After local assignment: test spam
   After nonlocal assignment: nonlocal spam
   After global assignment: nonlocal spam
   In global scope: global spam

このとおり、(デフォルトの) *ローカルな* 代入は *scope_test* 上の
*spam* への束縛を変更しませんでした。 "nonlocal" 代入は *scope_test*
上の *spam* への束縛を変更し、 "global" 代入はモジュールレベルの束縛を
変更しました。

またここから、 "global" 代入の前には *spam* に何も束縛されていなかった
ことも分かります。


9.3. クラス初見
===============

クラスでは、新しい構文を少しと、三つの新たなオブジェクト型、そして新た
な意味付けをいくつか取り入れています。


9.3.1. クラス定義の構文
-----------------------

クラス定義の最も単純な形式は、次のようになります:

   class ClassName:
       <statement-1>
       .
       .
       .
       <statement-N>

関数定義 ("def" 文) と同様、クラス定義が効果をもつにはまず実行しなけれ
ばなりません。 (クラス定義を "if" 文の分岐先や関数内部に置くことも、考
え方としてはありえます。)

実際には、クラス定義の内側にある文は、通常は関数定義になりますが、他の
文を書くこともでき、それが役に立つこともあります --- これについては後
で述べます。クラス内の関数定義は通常、メソッドの呼び出し規約で決められ
た独特の形式の引数リストを持ちます --- これについても後で述べます。

クラス定義に入ると、新たな名前空間が作成され、ローカルな名前空間として
使われます --- 従って、ローカルな変数に対する全ての代入はこの新たな名
前空間に入ります。特に、関数定義を行うと、新たな関数の名前はこの名前空
間に結び付けられます。

クラス定義から普通に (定義の終端に到達して) 抜けると、 *クラスオブジェ
クト (class object)* が生成されます。クラスオブジェクトは、基本的には
クラス定義で作成された名前空間の内容をくるむラッパー (wrapper) です。
クラスオブジェクトについては次の節で詳しく学ぶことにします。 (クラス定
義に入る前に有効だった) 元のローカルスコープが復帰し、生成されたクラス
オブジェクトは復帰したローカルスコープにクラス定義のヘッダで指定した名
前 (上の例では "ClassName") で結び付けられます。


9.3.2. クラスオブジェクト
-------------------------

クラスオブジェクトでは２種類の演算、属性参照とインスタンス生成をサポー
トしています。

*属性参照 (attribute reference)* は、Python におけるすべての属性参照で
使われている標準的な構文、 "obj.name" を使います。クラスオブジェクトが
生成された際にクラスの名前空間にあった名前すべてが有効な属性名です。従
って、以下のようなクラス定義では:

   class MyClass:
       """A simple example class"""
       i = 12345

       def f(self):
           return 'hello world'

"MyClass.i" と "MyClass.f" は妥当な属性参照であり、それぞれ整数と関数
オブジェクトを返します。クラス属性に代入を行うこともできます。従って、
"MyClass.i" の値を代入して変更できます。 "__doc__" も有効な属性で、そ
のクラスに属している docstring、この場合は ""A simple example class""
を返します。

クラスの *インスタンス化 (instantiation)* には関数記法を使います。クラ
スオブジェクトのことを、クラスの新しいインスタンスを返す、引数のない関
数のように扱ってください。上記クラスで例示すると:

   x = MyClass()

は、クラスの新しい *インスタンス (instance)* を生成し、そのオブジェク
トをローカル変数 "x" へ代入します。

このクラスのインスタンス生成操作 (クラスオブジェクトの "呼出し") を行
うと、空のオブジェクトを生成します。多くのクラスは、オブジェクトを作成
する際に、カスタマイズされた特定の初期状態になってほしいと望んでいます
。そのために、クラスには "__init__()" という名前の特別なメソッド定義す
ることができます。例えば次のようにします:

   def __init__(self):
       self.data = []

クラスが "__init__()" メソッドを定義している場合、クラスのインスタンス
を生成すると、新しく生成されたクラスインスタンスに対して自動的に
"__init__()" を呼び出します。従って、この例では、新たな初期済みのイン
スタンスを次のようにして得ることができます:

   x = MyClass()

もちろん、より大きな柔軟性を持たせるために、 "__init__()" メソッドに複
数の引数をもたせることができます。その場合、次の例のように、クラスのイ
ンスタンス生成操作に渡された引数は "__init__()" に渡されます。例えば、

   >>> class Complex:
   ...     def __init__(self, realpart, imagpart):
   ...         self.r = realpart
   ...         self.i = imagpart
   ...
   >>> x = Complex(3.0, -4.5)
   >>> x.r, x.i
   (3.0, -4.5)


9.3.3. インスタンスオブジェクト
-------------------------------

ところで、インスタンスオブジェクトを使うと何ができるのでしょうか？イン
スタンスオブジェクトが理解できる唯一の操作は、属性の参照です。有効な属
性名には (データ属性およびメソッドの) 二種類あります。

*Data attributes* correspond to "instance variables" in Smalltalk, and
to "data members" in C++.  Data attributes need not be declared; like
local variables, they spring into existence when they are first
assigned to.  For example, if "x" is the instance of "MyClass" created
above, the following piece of code will print the value "16", without
leaving a trace:

   x.counter = 1
   while x.counter < 10:
       x.counter = x.counter * 2
   print(x.counter)
   del x.counter

もうひとつのインスタンス属性は *メソッド (method)* です。メソッドとは
、オブジェクトに "属している" 関数のことです。(Python では、メソッドと
いう用語はクラスインスタンスだけのものではありません。オブジェクト型に
もメソッドを持つことができます。例えば、リストオブジェクトには、
append, insert, remove, sort などといったメソッドがあります。とはいえ
、以下では特に明記しない限り、クラスのインスタンスオブジェクトのメソッ
ドだけを意味するものとして使うことにします。)

インスタンスオブジェクトで有効なメソッド名は、そのクラスによります。定
義により、クラスの全ての関数オブジェクトである属性がインスタンスオブジ
ェクトの妥当なメソッド名に決まります。従って、例では、"MyClass.f" は関
数なので、"x.f" はメソッドの参照として有効です。しかし、"MyClass.i" は
関数ではないので、"x.i" はメソッドの参照として有効ではありません。
"x.f" は "MyClass.f" と同じものではありません --- 関数オブジェクトでは
なく、*メソッドオブジェクト (method object)* です。


9.3.4. メソッドオブジェクト
---------------------------

普通、メソッドはバインドされた直後に呼び出されます:

   x.f()

"MyClass" の例では、上のコードは文字列 "'hello world'" を返すでしょう
。しかしながら、必ずしもメソッドをその場で呼び出さなければならないわけ
ではありません。 "x.f" はメソッドオブジェクトであり、どこかに記憶して
おいて後で呼び出すことができます。例えば次のコードは:

   xf = x.f
   while True:
       print(xf())

"hello world" を時が終わるまで印字し続けるでしょう。

メソッドが呼び出されるときには実際には何が起きているのでしょうか？
"f()" の関数定義では引数を一つ指定していたにもかかわらず、上の例では
"x.f()" が引数なしで呼び出されています。引数はどうなったのでしょうか？
たしか、引数が必要な関数を引数無しで呼び出すと、 Python が例外を送出す
るはずです --- たとえその引数が実際には使われなくても…。

もう答は想像できているかもしれませんね: メソッドについて特別なこととし
て、インスタンスオブジェクトが関数の第1引数として渡されます。 例では、
"x.f()" という呼び出しは、 "MyClass.f(x)" と厳密に等価なものです。 一
般に、 *n* 個の引数リストもったメソッドの呼出しは、そのメソッドのイン
スタンスオブジェクトを最初の引数の前に挿入した引数リストで、メソッドに
対応する関数を呼び出すことと等価です。

もしまだメソッドの動作を理解できなければ、一度実装を見てみると事情がよ
く分かるかもしれません。インスタンスの非データ属性が参照されたときは、
そのインスタンスのクラスが検索されます。その名前が有効なクラス属性を表
している関数オブジェクトなら、インスタンスオブジェクトと見つかった関数
オブジェクト (へのポインタ) を抽象オブジェクト、すなわちメソッドオブジ
ェクトにパックして作成します。メソッドオブジェクトが引数リストと共に呼
び出されるとき、インスタンスオブジェクトと渡された引数リストから新しい
引数リストを作成して、元の関数オブジェクトを新しい引数リストで呼び出し
ます。


9.3.5. クラスとインスタンス変数
-------------------------------

一般的に、インスタンス変数はそれぞれのインスタンスについて固有のデータ
のためのもので、クラス変数はそのクラスのすべてのインスタンスによって共
有される属性やメソッドのためのものです:

   class Dog:

       kind = 'canine'         # class variable shared by all instances

       def __init__(self, name):
           self.name = name    # instance variable unique to each instance

   >>> d = Dog('Fido')
   >>> e = Dog('Buddy')
   >>> d.kind                  # shared by all dogs
   'canine'
   >>> e.kind                  # shared by all dogs
   'canine'
   >>> d.name                  # unique to d
   'Fido'
   >>> e.name                  # unique to e
   'Buddy'

名前とオブジェクトについて で議論したように、共有データはリストや辞書
のような *mutable* オブジェクトが関与すると驚くべき効果を持ち得ます。
例えば、以下のコードの *tricks* リストはクラス変数として使われるべきで
はありません、なぜならたった一つのリストがすべての *Dog* インスタンス
によって共有されることになり得るからです:

   class Dog:

       tricks = []             # mistaken use of a class variable

       def __init__(self, name):
           self.name = name

       def add_trick(self, trick):
           self.tricks.append(trick)

   >>> d = Dog('Fido')
   >>> e = Dog('Buddy')
   >>> d.add_trick('roll over')
   >>> e.add_trick('play dead')
   >>> d.tricks                # unexpectedly shared by all dogs
   ['roll over', 'play dead']

このクラスの正しい設計ではインスタンス変数を代わりに使用するべきです:

   class Dog:

       def __init__(self, name):
           self.name = name
           self.tricks = []    # creates a new empty list for each dog

       def add_trick(self, trick):
           self.tricks.append(trick)

   >>> d = Dog('Fido')
   >>> e = Dog('Buddy')
   >>> d.add_trick('roll over')
   >>> e.add_trick('play dead')
   >>> d.tricks
   ['roll over']
   >>> e.tricks
   ['play dead']


9.4. いろいろな注意点
=====================

インスタンスとクラスの両方で同じ属性名が使用されている場合、属性検索は
インスタンスが優先されます。

   >>> class Warehouse:
   ...    purpose = 'storage'
   ...    region = 'west'
   ...
   >>> w1 = Warehouse()
   >>> print(w1.purpose, w1.region)
   storage west
   >>> w2 = Warehouse()
   >>> w2.region = 'east'
   >>> print(w2.purpose, w2.region)
   storage east

データ属性は、メソッドから参照できると同時に、通常のオブジェクトのユー
ザ ("クライアント") からも参照できます。言い換えると、クラスは純粋な抽
象データ型として使うことができません。実際、 Python では、データ隠蔽を
補強するための機構はなにもありません --- データの隠蔽はすべて規約に基
づいています。 (逆に、C 言語で書かれた Python の実装では実装の詳細を完
全に隠蔽し、必要に応じてオブジェクトへのアクセスを制御できます。この機
構は C 言語で書かれた Python 拡張で使うことができます。)

クライアントはデータ属性を注意深く扱うべきです --- クライアントは、メ
ソッドが維持しているデータ属性の不変式を踏みにじり、台無しにするかもし
れません。クライアントは、名前の衝突が回避されている限り、メソッドの有
効性に影響を及ぼすことなくインスタンスに独自の属性を追加することができ
る、ということに注意してください --- ここでも、名前付けの規約は頭痛の
種を無くしてくれます。

メソッドの中から、データ属性を (または別のメソッドも！) 参照するための
短縮された記法はありません。私は、この仕様がメソッドの可読性を高めてい
ると感じています。あるメソッドを眺めているときにローカルな変数とインス
タンス変数をはっきり区別できるからです。

よく、メソッドの最初の引数を "self" と呼びます。この名前付けは単なる慣
習でしかありません。 "self" という名前は、 Python では何ら特殊な意味を
持ちません。とはいえ、この慣行に従わないと、コードは他の Python プログ
ラマにとってやや読みにくいものとなります。また、 *クラスブラウザ
(class browser)* プログラムがこの慣行をあてにして書かれているかもしれ
ません。

クラス属性である関数オブジェクトはいずれも、そのクラスのインスタンスの
ためのメソッドを定義しています。関数定義は、テキスト上でクラス定義の中
に入っている必要はありません。関数オブジェクトをクラスのローカルな変数
の中に代入するのも OK です。例えば以下のコードのようにします:

   # Function defined outside the class
   def f1(self, x, y):
       return min(x, x+y)

   class C:
       f = f1

       def g(self):
           return 'hello world'

       h = g

これで、 "f" 、 "g" 、および "h" は、すべて "C" の属性であり関数オブジ
ェクトを参照しています。従って、これら全ては、 "C" のインスタンスのメ
ソッドとなります --- "h" は "g" と全く等価です。これを実践しても、大抵
は単にプログラムの読者に混乱をもたらすだけなので注意してください。

メソッドは、 "self" 引数のメソッド属性を使って、他のメソッドを呼び出す
ことができます:

   class Bag:
       def __init__(self):
           self.data = []

       def add(self, x):
           self.data.append(x)

       def addtwice(self, x):
           self.add(x)
           self.add(x)

メソッドは、通常の関数と同じようにしてグローバルな名前を参照します。あ
るメソッドに関するグローバルスコープは、その定義を含むモジュールです。
(クラスはグローバルなスコープとして用いられることはありません。) メソ
ッドでグローバルなデータを使う良い理由はほとんどありませんが、グローバ
ルなスコープを使うべき場面は多々あります。一つ挙げると、メソッド内から
、グローバルなスコープに import された関数やモジュールや、そのモジュー
ル中で定義された関数やクラスを使うことができます。通常、メソッドの入っ
ているクラス自体はグローバルなスコープ内で定義されています。次の節では
、メソッドが自分のクラスを参照する理由として正当なものを見てみましょう
。

個々の値はオブジェクトなので、 *クラス* (*型* とも言います) を持ってい
ます。それは "object.__class__" に保持されています。


9.5. 継承
=========

言うまでもなく、継承の概念をサポートしない言語機能は "クラス" と呼ぶに
値しません。派生クラス (derived class) を定義する構文は次のようになり
ます:

   class DerivedClassName(BaseClassName):
       <statement-1>
       .
       .
       .
       <statement-N>

基底クラス (base class) の名前 "BaseClassName" は、派生クラス定義の入
っているスコープで定義されていなければなりません。基底クラス名のかわり
に任意の式を入れることもできます。これは次の例のように、基底クラスが別
モジュールで定義されているときに便利なことがあります:

   class DerivedClassName(modname.BaseClassName):

派生クラス定義の実行は、基底クラスの場合と同じように進められます。クラ
スオブジェクトが構築される時、基底クラスが記憶されます。記憶された基底
クラスは、属性参照を解決するために使われます。要求された属性がクラスに
見つからなかった場合、基底クラスに検索が進みます。この規則は、基底クラ
スが他の何らかのクラスから派生したものであった場合、再帰的に適用されま
す。

派生クラスのインスタンス化では、特別なことは何もありません。
"DerivedClassName()" はクラスの新たなインスタンスを生成します。メソッ
ドの参照は次のようにして解決されます。まず対応するクラス属性が検索され
ます。検索は、必要に応じ、基底クラス連鎖を下って行われ、検索の結果とし
て何らかの関数オブジェクトがもたらされた場合、メソッド参照は有効なもの
となります。

派生クラスは基底クラスのメソッドを上書き (override) することができます
。メソッドは同じオブジェクトの別のメソッドを呼び出す際に何ら特殊な権限
を持ちません。このため、ある基底クラスのメソッドが、同じ基底クラスで定
義されているもう一つのメソッド呼び出しを行っている場合、派生クラスで上
書きされた何らかのメソッドが呼び出されることになるかもしれません。
(C++ プログラマへ:  Python では、すべてのメソッドは事実上 "virtual" で
す。)

派生クラスで上書きしているメソッドでは、基底クラスの同名のメソッドを置
き換えるのではなく、拡張したいのかもしれません。基底クラスのメソッドを
直接呼び出す簡単な方法があります。単に "BaseClassName.methodname(self,
arguments)" を呼び出すだけです。この仕様は、場合によってはクライアント
でも役に立ちます。 (この呼び出し方が動作するのは、基底クラスがグローバ
ルスコープの "BaseClassName" という名前でアクセスできるときだけです。)

Python には継承に関係する 2 つの組み込み関数があります:

* "isinstance()" を使うとインスタンスの型が調べられます。
  "isinstance(obj, int)" は "obj.__class__" が "int" や "int" の派生ク
  ラスの場合に限り "True" になります。

* "issubclass()" を使うとクラスの継承関係が調べられます。 "bool" は
  "int" のサブクラスなので "issubclass(bool, int)" は "True" です。し
  かし、 "float" は "int" のサブクラスではないので "issubclass(float,
  int)" は "False" です。


9.5.1. 多重継承
---------------

Python では、多重継承 (multiple inheritance) の形式もサポートしていま
す。複数の基底クラスをもつクラス定義は次のようになります:

   class DerivedClassName(Base1, Base2, Base3):
       <statement-1>
       .
       .
       .
       <statement-N>

ほとんどのシンプルな多重継承において、親クラスから継承される属性の検索
は、深さ優先で、左から右に、そして継承の階層の中で同じクラスが複数出て
くる（訳注: ダイアモンド継承と呼ばれます）場合に２度探索をしない、と考
えることができます。なので、 "DerivedClassName" にある属性が存在しない
場合、まず "Base1" から検索され、そして（再帰的に） "Base1" の基底クラ
スから検索され、それでも見つからなかった場合は "Base2" から検索される
、といった具合になります。

実際には、それよりもう少しだけ複雑です。協調的な "super()" の呼び出し
のためにメソッドの解決順序は動的に変更されます。このアプローチは他の多
重継承のある言語で call-next-method として知られており、単一継承しかな
い言語の super 呼び出しよりも強力です。

多重継承の全ての場合に 1 つかそれ以上のダイヤモンド継承 (少なくとも 1
つの祖先クラスに対し最も下のクラスから到達する経路が複数ある状態) があ
るので、動的順序付けが必要です。例えば、全ての新形式のクラスは
"object" を継承しているので、どの多重継承でも "object" へ到達するため
の道は複数存在します。基底クラスが複数回アクセスされないようにするため
に、動的アルゴリズムで検索順序を直列化し、各クラスで指定されている祖先
クラスどうしの左から右への順序は崩さず、各祖先クラスを一度だけ呼び出し
、かつ単調になる (つまり祖先クラスの検索順序に影響を与えずにクラスをサ
ブクラス化できる) ようにします。まとめると、これらの特徴のおかげで信頼
性と拡張性のある多重継承したクラスを設計することができるのです。さらに
詳細を知りたければ、 https://www.python.org/download/releases/2.3/mro/
を見てください。


9.6. プライベート変数
=====================

オブジェクトの中からしかアクセス出来ない "プライベート" インスタンス変
数は、 Python にはありません。しかし、ほとんどの Python コードが従って
いる慣習があります。アンダースコアで始まる名前 (例えば "_spam") は、 (
関数であれメソッドであれデータメンバであれ) 非 public なAPIとして扱い
ます。これらは、予告なく変更されるかもしれない実装の詳細として扱われる
べきです。

クラスのプライベートメンバについて適切なユースケース(特にサブクラスで
定義された名前との衝突を避ける場合)があるので、名前マングリング (*name
mangling*) と呼ばれる、限定されたサポート機構があります。 "__spam" (先
頭に二個以上の下線文字、末尾に一個以下の下線文字) という形式の識別子は
、 "_classname__spam" へとテキスト置換されるようになりました。ここで
"classname" は、現在のクラス名から先頭の下線文字をはぎとった名前になり
ます。このような難号化 (mangle) は、識別子の文法的な位置にかかわらず行
われるので、クラス定義内に現れた識別子全てに対して実行されます。

名前マングリングは、サブクラスが内部のメソッド呼び出しを壊さずにメソッ
ドをオーバーライドするのに便利です。例えば:

   class Mapping:
       def __init__(self, iterable):
           self.items_list = []
           self.__update(iterable)

       def update(self, iterable):
           for item in iterable:
               self.items_list.append(item)

       __update = update   # private copy of original update() method

   class MappingSubclass(Mapping):

       def update(self, keys, values):
           # provides new signature for update()
           # but does not break __init__()
           for item in zip(keys, values):
               self.items_list.append(item)

上の例は、もし仮に "MappingSubclass" に "__update" 識別子を実装したと
してもきちんと動きます。 その理由は、 "Mapping" クラスではその識別子を
"_Mapping__update" に、 "MappingSubclass" クラスでは
"_MappingSubclass__update" にそれぞれ置き換えるからです。

難号化の規則は主に不慮の事故を防ぐためのものだということに注意してくだ
さい; 確信犯的な方法で、プライベートとされている変数にアクセスしたり変
更することは依然として可能なのです。デバッガのような特殊な状況では、こ
の仕様は便利ですらあります。

"exec()" や "eval()" へ渡されたコードでは、呼出し元のクラス名を現在の
クラスと見なさないことに注意してください。この仕様は "global" 文の効果
と似ており、その効果もまた同様に、バイトコンパイルされたコードに制限さ
れています。同じ制約が "getattr()" と "setattr()" と "delattr()" にも
適用されます。また、"__dict__" を直接参照するときにも適用されます。


9.7. 残りのはしばし
===================

Pascal の "レコード (record)" や、C 言語の "構造体 (struct)" のような
、名前つきのデータ要素を一まとめにするデータ型があると便利なことがあり
ます。慣用的な手法として、この目的のために "dataclasses" を使用します
。

   from dataclasses import dataclass

   @dataclass
   class Employee:
       name: str
       dept: str
       salary: int

   >>> john = Employee('john', 'computer lab', 1000)
   >>> john.dept
   'computer lab'
   >>> john.salary
   1000

ある特定の抽象データ型を要求する Python コードの断片に、そのデータ型の
メソッドをエミュレーションするクラスを代わりに渡すことができます。例え
ば、ファイルオブジェクトから何らかのデータを構築する関数がある場合、
"read()" と "readline()" を持つクラスを定義して、ファイルではなく文字
列バッファからデータを取得するようにしておき、引数として渡すことができ
ます。

インスタンスメソッドオブジェクトにも属性があります。 "m.__self__" はメ
ソッド "m()" の属しているインスタンスオブジェクトで、 "m.__func__" は
メソッドに対応する関数オブジェクトです。


9.8. イテレータ (iterator)
==========================

すでに気づいているでしょうが、 "for" 文を使うとほとんどのコンテナオブ
ジェクトにわたってループを行うことができます:

   for element in [1, 2, 3]:
       print(element)
   for element in (1, 2, 3):
       print(element)
   for key in {'one':1, 'two':2}:
       print(key)
   for char in "123":
       print(char)
   for line in open("myfile.txt"):
       print(line, end='')

こういう要素へのアクセス方法は明確で簡潔で使い易いものです。イテレータ
の活用は Python へ広く行き渡り、統一感を持たせています。裏では "for"
文はコンテナオブジェクトに対して "iter()" 関数を呼んでいます。関数は、
コンテナの中の要素に1つずつアクセスする "__next__()" メソッドが定義さ
れているイテレータオブジェクトを返します。これ以上要素が無い場合は、
"__next__()" メソッドは "StopIteration" 例外を送出し、その通知を受け
"for" ループは終了します。組み込みの "next()" 関数を使って
"__next__()" メソッドを直接呼ぶこともできます; この例は関数がどう働く
のかを示しています:

   >>> s = 'abc'
   >>> it = iter(s)
   >>> it
   <str_iterator object at 0x10c90e650>
   >>> next(it)
   'a'
   >>> next(it)
   'b'
   >>> next(it)
   'c'
   >>> next(it)
   Traceback (most recent call last):
     File "<stdin>", line 1, in <module>
       next(it)
   StopIteration

イテレータプロトコルの裏にある仕組みを観察していれば、自作のクラスにイ
テレータとしての振舞いを追加するのは簡単です。 "__next__()" メソッドを
持つオブジェクトを返す "__iter__()" メソッドを定義するのです。クラスが
"__next__()" メソッドを定義している場合、 "__iter__()" メソッドは単に
"self" を返すことも可能です:

   class Reverse:
       """Iterator for looping over a sequence backwards."""
       def __init__(self, data):
           self.data = data
           self.index = len(data)

       def __iter__(self):
           return self

       def __next__(self):
           if self.index == 0:
               raise StopIteration
           self.index = self.index - 1
           return self.data[self.index]

   >>> rev = Reverse('spam')
   >>> iter(rev)
   <__main__.Reverse object at 0x00A1DB50>
   >>> for char in rev:
   ...     print(char)
   ...
   m
   a
   p
   s


9.9. ジェネレータ (generator)
=============================

*ジェネレータ* は、イテレータを作成するための簡潔で強力なツールです。
ジェネレータは通常の関数のように書かれますが、何らかのデータを返すとき
には "yield" 文を使います。そのジェネレータに対して "next()" が呼び出
されるたびに、ジェネレータは以前に中断した処理を再開します (ジェネレー
タは、全てのデータ値と最後にどの文が実行されたかを記憶しています)。以
下の例を見れば、ジェネレータがとても簡単に作成できることがわかります:

   def reverse(data):
       for index in range(len(data)-1, -1, -1):
           yield data[index]

   >>> for char in reverse('golf'):
   ...     print(char)
   ...
   f
   l
   o
   g

ジェネレータでできることは、前の節で解説したクラスを使ったイテレータで
も実現できます。ジェネレータの定義がコンパクトになるのは "__iter__()"
メソッドと "__next__()" メソッドが自動で作成されるからです。

ジェネレータのもう一つの重要な機能は、呼び出しごとにローカル変数と実行
状態が自動的に保存されるということです。これにより、 "self.index" や
"self.data" といったインスタンス変数を使ったアプローチよりも簡単に関数
を書くことができるようになります。

メソッドを自動生成したりプログラムの実行状態を自動保存するほかに、ジェ
ネレータは終了時に自動的に "StopIteration" を送出します。これらの機能
を組み合わせると、通常の関数を書くのと同じ労力で、簡単にイテレータを生
成できます。


9.10. ジェネレータ式
====================

単純なジェネレータなら式として簡潔にコーディングできます。 その式はリ
スト内包表記に似た構文を使いますが、角括弧ではなく丸括弧で囲います。
ジェネレータ式は、関数の中でジェネレータをすぐに使いたいような状況のた
めに用意されています。 ジェネレータ式は完全なジェネレータの定義よりコ
ンパクトですが、ちょっと融通の効かないところがあります。 同じ内容を返
すリスト内包表記よりはメモリに優しいことが多いという利点があります。

例:

   >>> sum(i*i for i in range(10))                 # sum of squares
   285

   >>> xvec = [10, 20, 30]
   >>> yvec = [7, 5, 3]
   >>> sum(x*y for x,y in zip(xvec, yvec))         # dot product
   260

   >>> unique_words = set(word for line in page  for word in line.split())

   >>> valedictorian = max((student.gpa, student.name) for student in graduates)

   >>> data = 'golf'
   >>> list(data[i] for i in range(len(data)-1, -1, -1))
   ['f', 'l', 'o', 'g']

-[ 脚注 ]-

[1] 例外が一つあります。モジュールオブジェクトには、秘密の読取り専用の
    属性 "__dict__" があり、モジュールの名前空間を実装するために使われ
    ている辞書を返します; "__dict__" という名前は属性ですが、グローバ
    ルな名前ではありません。この属性を利用すると名前空間の実装に対する
    抽象化を侵すことになるので、プログラムを検死するデバッガのような用
    途に限るべきです。
