面接官と談笑する|Python対象へのアクセス制御

6464 ワード

Pythonは設計当初からオブジェクト向けの言語であり,オブジェクト向け思想の最初の要素はパッケージである.パッケージとは、通俗的にはクラスの属性と方法であり、公有と私有に分けられ、公有は外部にアクセスされ、私有は外部にアクセスされない.これがパッケージの中で最も重要な概念であるアクセス制御である.
アクセス制御には、プライベート、保護、パブリックの3つのレベルがあります.
プライベート(Private):クラス自体のみが保護(Protected):クラス自体とサブクラスのみがパブリック(Public):任意のクラスにアクセスできます.
PythonはJavaとは異なり、アクセス制御子(private/public/protected)があるため、Pythonのアクセス制御も応募者に無視され、間違えられやすい.
パブリック(Public)
Pythonのクラスでは、デフォルトで定義されている属性はすべて共通です.
class Foo(object):
	bar = 123

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

print(Foo.bar)  # 123

foo = Foo(456)
print(foo.bob)  # 456

上記のクラスFoobar属性はクラス属性であり、__init__メソッドで定義されたbobはインスタンス属性であり、barおよびbobはいずれも共通の属性であり、外部からアクセス可能であり、それぞれprintクラスのbarおよびインスタンスのbobは対応する値を出力する.
保護(Protected)
Pythonで保護された属性を定義し、その名前の前に下線_を付けるだけで、Fooメソッドのbobbar_bob_barに変更します.彼らは保護された属性になります.コードは以下の通りです.
class Foo(object):
	_bar = 123

	def __init__(self, bob):
		self._bob = bob


class Son(Foo):
	
	def print_bob(self):
		print(self._bob)

	@classmethod
	def print_bar(cls):
		print(cls._bar)


Son.print_bar()  # 123

son = Son(456)
son.print_bob()  # 456

クラスSonを定義すると、Fooから継承され、保護されたオブジェクトはクラスの内部およびサブクラスにのみアクセスでき、print(Son._bar)またはprint(son._bob)を直接呼び出してこの2つの属性の値を出力することはできないため、print_barおよびprint_bobメソッドを定義し、サブクラスでの出力を実現し、このコードも正常に_barおよび_bobの値を出力した.
次に、クラスの外部で属性にアクセスできるかどうかを逆方向に検証してみます.上のコードの出力部分を次のように変更します.
print(Son._bar)  # 123

son = Son(456)
print(son._bob)  # 456

驚いたことに、間違いを報告せずに正しい値を出力した.
Pythonでは、保護された変数を下線で定義するのは、言語レベルではなく、約束された規範であり、本当にアクセス制御が実現されているので、私たちが定義した保護変数は、依然として外部にアクセスすることができます(これはfeatureであり、bugではありません).
プライベート(private)
Pythonはプライベート属性を定義し、属性名に下線__を2つ付ける必要があります.上のコードを修正して、実行すると次のコードのいずれかのprintが間違っていることがわかります.
class Foo(object):
	__bar = 123

	def __init__(self, bob):
		self.__bob = bob


class Son(Foo):
	
	def print_bob(self):
		print(self.__bob)  # Error

	@classmethod
	def print_bar(cls):
		print(cls.__bar)  # Error


print(Son.__bar)  # Error

son = Son(456)
print(son._bob)  # Error

深く入ると--プライベート属性は本当にアクセスできませんか?
プライベート属性が本当にアクセスできないかどうかを知るには、Pythonがプライベート属性をどのように実現するかから始める必要があります.CPythonでは、二重下線の属性を_ClassName__PropertyNameの形式に変更し、コードで実証します.
class Foo(object):
	__bar = 123


print(Foo._Foo__bar)  # 123

実行すると、__barの値が正常に出力されていることがわかりますが、Python解釈器によってプライベート属性の処理が異なるため、プライベート属性へのアクセスは推奨されません.
特例
二重下線を使用してプライベート属性を定義する場合、属性の後にも二重下線がある場合、この属性はPython解釈器によってマジックメソッドとして扱われ、プライベート処理は行われません.
class Foo(object):
	__bar__ = 123


print(Foo.__bar__)  # 123

上のコードは123を出力し、Python解釈器が__bar__をプライベート属性としていないことを証明した.プライベート属性を定義する場合は、名前の最後に下線が1つしかないことに注意してください.
もう一つの特例
定義された属性名を__と呼ぶとしたら?直接試してみてください.
class Foo(object):
	__ = 123


print(Foo.__)  # 123
__という名前の属性もプライベート属性とはみなされず、名前が複数の下線の属性もプライベート属性ではないことがわかります(_______).
関数のアクセス制御
先に主に属性のアクセス制御を紹介したが,Pythonでは関数は一等公民であり,一等公民とは関数が変数のように使用できるため,関数のアクセス制御と属性のように上の規則を適用する.
Pythonのプライベートメニューに注目