5.1 アクセスレベル
コンストラクタの名前__init__ってちょっと変だなって思ったことある?これからよく目にすることになるよ。
Pythonにはクラスの属性やメソッドへのアクセスを制御するためのいろんなアクセスレベルがあって、データの可視性と保護を助けてくれるんだ。アクセス制御の主な仕組みには、属性やメソッド名の前にアンダースコア(_ や __)を使うことが含まれているよ。
慣習の使い方
アンダースコア一つ _ は、クラスやモジュールの外で使いたくない属性やメソッドにつけるんだ。禁止ってわけじゃないけど、コードの読みやすさと保守性を考えて、これは守ったほうがいいよ。
アンダースコア二つ __ は、外部からの意図しないアクセスから保護したい、本当にプライベートにしたい属性やメソッドに使うんだ。name mangling メカニズムが、それを少しアクセスしにくくするけど、特別な名前を使えばまだアクセスできるよ。
パブリック (public) フィールドとメソッド
パブリックな属性とメソッド どこからでもアクセス可能だよ。 Pythonでは、名前がアンダースコアで始まらない限り、デフォルトですべての属性やメソッドはパブリックなんだ。
class MyClass:
def __init__(self):
self.public_attribute = "I am public"
def public_method(self):
return "This is a public method"
obj = MyClass()
print(obj.public_attribute) # アクセス可能
print(obj.public_method()) # アクセス可能
Pythonのアクセスレベルによって、カプセル化が実現されていて、特に非パブリックなフィールドやメソッドによって行われているんだ。
5.2 非パブリックフィールドとメソッド
プロテクトされた (protected) フィールドとメソッド
プロテクトされた属性とメソッドは名前の前にアンダースコア_をつけることで示されていて、クラスやそのサブクラスで内部使用を意図しているんだ。この慣習は、プログラマーに対してデータがクラス外で使用されないようにするためのものだよ。
class MyClass:
def __init__(self):
self._protected_attribute = "I am protected"
def _protected_method(self):
return "This is a protected method"
obj = MyClass()
print(obj._protected_attribute) # アクセス可能、でも推奨されない
print(obj._protected_method()) # アクセス可能、でも推奨されない
プライベート (private) フィールドとメソッド
Pythonでプライベートな属性とメソッドは名前の前にアンダースコア二つ__をつけることで示されるよ。これらの属性とメソッドはクラス内でだけ使用されることを意図していて、その主な目的は内部実装を隠し、データを外部からの意図しない変更や使用から保護することだよ。
こういった属性やメソッドへの直接アクセスを外部コードから防ぐために、Pythonはname mangling(名前の歪曲)として知られる特別なメカニズムを使用するよ。このメカニズムは、クラス名のプレフィックスを加えることでプライベート属性名を自動的に変更するんだ。例えば、クラスMyClass内のプライベート属性__private_attributeは内部的な名前_MyClass__private_attributeに変換されるよ。
これによって、データを意図しないアクセスから保護しつつ、クラス内部での作業は可能になるんだ。ただし、name manglingメカニズムは絶対的な保護ではないことを覚えておいてね — 経験豊富なプログラマーは変更された名前を使ってこれらにアクセスすることができるんだ。
じゃあ、これが実際にどう機能するか見てみよう:
class MyClass:
def __init__(self):
self.__private_attribute = "I am private"
def __private_method(self):
return "This is a private method"
def access_private_method(self):
return self.__private_method()
obj = MyClass()
# print(obj.__private_attribute) # エラー、直接アクセス不可
# print(obj.__private_method()) # エラー、直接アクセス不可
print(obj.access_private_method()) # クラスのパブリックメソッドを通じてアクセス可能
この例からわかるように、プライベート属性やメソッドへの直接アクセスはエラーを引き起こすんだ。でもPythonは、変更された名前を使ってアクセスする能力を維持しているんだよ。例えば、以下のように"歪曲された"名前を使ってプライベート属性にアクセスできるんだ:
class MyClass:
def __init__(self):
self.__private_attribute = "I am private"
obj = MyClass()
print(obj._MyClass__private_attribute) # 出力: I am private
"歪曲された"名前を使ったアクセスは可能だけど、それを避けたほうがいいよ。なぜなら、それはカプセル化の原則に違反して、コードの安定性を損なう可能性があるからね。
Pythonが属性名をどのように変更するかを見るには、オブジェクトのすべてのアクセス可能な属性とメソッドを表示する、組み込み関数dir()を使えるよ:
class MyClass:
def __init__(self):
self.__private_attribute = "I am private"
obj = MyClass()
print(dir(obj)) # オブジェクトのすべての属性とメソッドを出力、"歪曲された"名前を含む
dir() 関数の結果として、オブジェクトのすべての属性とメソッドのリストが表示され、その中に_MyClass__private_attributeも含まれていることが確認できるよ。これはname manglingメカニズムを確認するものだね。
5.3 自動メソッド呼び出し
コンストラクタを使うときに気づいたかもしれないけど、__init__メソッドは自動的に呼び出されるんだ。
こういう状況は実はたくさんあって、そのためのメソッドもたくさんあるよ。例を挙げると:
メソッド __str__
オブジェクトに__str__メソッドがあると、オブジェクトを文字列に変換しようとするときに自動的に呼び出されるよ。例えばprint()やstr()関数を使うときにね。
class Cat:
def __init__(self, name, age):
self.name = name
self.age = age
def __str__(self):
return f"{self.name} is {self.age} years old"
cat = Cat("Barsik", 5)
print(cat) # 出力: Barsik is 5 years old
メソッド __len__
オブジェクトに__len__メソッドがあると、「長さ」を求めようとするときに自動的に呼び出される — len()関数が使われるよ。例:
class MyList:
def __init__(self, items):
self.items = items
def __len__(self):
return len(self.items)
my_list = MyList([1, 2, 3])
print(len(my_list)) # 出力: 3
こういった「特殊なメソッド」はまだまだいっぱいあって、使うのが楽しいから楽しみにしてて:)
GO TO FULL VERSION