非公開変数
Python にはプライベート変数、プライベート関数というものがありません。
クラスを利用するときでも内部データにアクセスしないようにしているだけで、実際にはアクセスできてしまいます。
code: 0708_class_variables_isnot_private.py
class Artist1():
def __init__(self, firstname='', lastname=''):
self.firstname = firstname
self.lastname = lastname
class Artist2():
def __init__(self, firstname='', lastname=''):
self.__firstname = firstname
self.__lastname = lastname
queen = Artist1()
print(f'\n{queen.__class__}:', dir(queen))
print(queen.firstname)
whitesnake = Artist2()
print(f'\n{whitesnake.__class__}:', dir(whitesnake))
print(whitesnake.__firstname)
2つのクラス定義の違いは、Artist2では__変数名 のように内部変数に2つのアンダースコア(double underscore)をつけていることです。
これは擬似的にプライベート変数のように振る舞っているだけで、実際には、クラス名.__変数名 としてアクセスできてしまいます。
次の例を見てみましょう。これは座標を保持するようなことを想定したクラスです。
code: 0709_class_variables_isnot_private.py
class Point:
points = 0
def __init__(self, x=0, y=0):
self.x = x
self.y = y
self.points += 1
p1 = Point()
print(p1.points)
p2 = Point()
print(p2.points)
__init__() の中で self.points に1を加えています。
これは、インスタンスオブジェクトが持っているアトリビュート points に1を加えたことになります。だから、このクラスの定義では、 points の値はいつも1になります。
これを次のように書くとどうなるか確かめてみましょう。
code: 0710_class_variables_isnot_private.py
class Point:
points = 0
def __init__(self, x=0, y=0):
self.x = x
self.y = y
self.__class__.points += 1
p1 = Point()
print(p1.points)
p2 = Point()
print(p2.points)
__init__() の中で self.__class__.points に1を加えています。
これは、クラスオブジェクトが持っているアトリビュート points に1を加えたことになります。つまり、このクラスの定義では、インスタンスを作成するたびに points の値が1に増えていくことになります。
状態を保持するようなプログラムになるのですが、インスタンスを作成した時点でのpointの値が不明瞭になることが理解できるでしょう。
非公開を期待しているアトリビュートへアクセスしない方が安全です。
2つのアンダースコアで始まる変数であっても、よく参照するものを上げておきます。
__name__ :
スクリプトが実行されていると文字列__main__ がセットされる
関数オブジェクトであれば関数名がセットされる
モジュールのスクリプトであればモジュール名がセットされる
__file__: 実行しているスクリプトのファイル名
__doc__: スクリプトファイル、関数、クラスなどで定義しているdocstrings