2019年1月15日火曜日

クラスの変数とインスタンス変数、selfのはなし

selfとは何か、また、クラス変数とインスタンス変数の違いについて、調べたことをメモする。

  • selfはインスタンスに関するものであるということ。メソッドの第一引数はインスタンスに作用することを明示している。変数として'self.(=自分自身のオブジェクト名.)'をつけるのは自分自身をインスタンシェートしたときにオブジェクト固有情報として扱うものであることを意味する。
  • クラス変数とは、クラス共通の変数。設計図であるクラスに共通なので、オブジェクト外部から変更を行った場合、変更は設計図の変更を意味し、そのクラスから作ったすべてのオブジェクトのクラス変数が参照渡しで動的に変更されるオブジェクト内部から変更を行った場合、すなわちメソッドで扱った場合、関数には値渡しされる、すなわちオブジェクト固有情報として複製が渡される。
  • インスタンス変数とはオブジェクト固有の変数で、インスタンシェート後に各々のオブジェクトで管理される変数。
  • グローバル変数のスコープはクラスも包括する。
  • クラス内ではローカル変数が使える。

code

01 Param = 'global' # global
02 class ParamTest(object):
03     Param = 'class' # class
04     def __init__(self):
05         pass
06 #        self.Param = 'instance'
07     def duplicate(self):
08         self.Param += 'Copy' # class's copy
09     def Get(self):
10         print(Param) # global
11     def Get2(self):
12         print(self.Param) # class or instance
13         
14 if __name__ == '__main__':
15     ParamTest.Param += '2'
16     ob1 = ParamTest()
17     ParamTest.Param += '3'
18     ob2 = ParamTest()
19     print(ob1.Param)
20     ob1.duplicate()
21     print(ob1.Param)
22     print(ob2.Param)
23     ob1.Get()
24     ob2.Get()
25     ob1.Get2()
26     ob2.Get2()
27     ParamTest.Get(ob1)
28     ParamTest.Get2(ob1)
実行結果

class23
class23Copy
class23
global
global
class23Copy
class23
global
class23Copy
  • 01:グローバル変数Paramを定義。
  • 03:クラス変数Paramを定義。
  • 06:コンストラクタに'コメントで'インスタンス変数Paramを定義。これをするとクラス変数が無効になる。
  • 08:クラス変数Paramに内部からアクセスしている。結果的にクラス変数Paramがインスタンス変数Paramに値渡しされる形で定義される。値渡しされていることが分かるように既存の変数に追記する形で定義している。クラス変数に内部からアクセスするときは参照のみ可能で、'self.'を付けて参照することで同名の('self.'付の)インスタンス変数が定義され、クラス変数の内容が値渡しされる。
  • 10:グローバル変数Paramを参照。01行目の定義がなければ参照先が無いためエラーとなる。
  • 12:duplicate実行後はインスタンス変数が参照され、実行前はクラス変数(のコピー)が参照される。
  • 15,17:ParamTestクラスのクラス変数Paramに外部からアクセスしている。クラス変数を変更すると定義済みのオブジェクトのクラス変数も変更されることが分かるように、16,18行目でオブジェクトをインスタンシェートしている。結果から分かるように、何れも'class23'となっており、参照渡しされている。
  • 20-22:duplicate実行によりクラス変数と同名のインスタンス変数が定義されることを確認している。ob1.Paramはインスタンス変数を参照しており、ob2.Paramはクラス変数を参照している。外部・内部に因らず、同名のクラス変数とインスタンス変数がある場合はインスタンス変数が優先される。25,26行目は内部からアクセスした場合で、結果は21,22行目と同じなのが分かる。
  • 27,28:メンバ関数(=インスタンス関数=クラス関数=メソッド)にクラスから直接アクセスしている。この書き方から、メソッドの第一引数をselfとしている理解が伺える。Pythonのメソッドはクラスから直接アクセスでき、第一引数にオブジェクト名を指定することで指定したオブジェクトのメソッドを実行することができる。

selfについて

クラスの関数(コンストラクタを含む)の第一引数は必ず自分自身を現す仮引数である必要がある(何も指定しないとエラーになる)。仮引数は(ここで仮引数と呼んでいるように仮引数なので)selfでなくてもよいが、可読性のための作法としてselfとする。
self第一引数の意味するところは、クラスをインスタンスしたときに、その関数がそのオブジェクトにのみ作用することを明示するためである。別の見方として、上の例の通り、クラスから直接メソッドにアクセスする手段があり、その際の第一引数にオブジェクト名を指定する。
変数の頭につけるselfも同様で、それがインスタンス変数であることを宣言している。

0 件のコメント:

コメントを投稿