30. Python에서의 캡슐화 – 정보 은닉을 위한 접근 지정

안녕하세요. 언휴예요.

 

OOP의 주요 특징인 캡슐화는 여러 가지 멤버를 하나의 형식으로 묶는 과정을 말하며 클래스를 통해 구현합니다. 특히 클래스에 멤버를 정의할 때 어느 영역에서 해당 멤버에 접근할 수 있는지를 지정할 수 있게 하여 주요 멤버에 외부에서 접근하여 잘못된 상태가 만들어지지 않게 만들 수 있게 지원합니다. 이러한 특징은 접근 지정을 통한 정보 은닉이라고 부릅니다.

 

예를 들어 유닛의 멤버 필드 중에 체력이 0에서 100 사이를 유지한다고 가정합시다. 그리고 운동하면 체력이 1 증가하고 술 마시면 1 감소하게 작성했고요. 그런데 유닛을 사용하는 부분에서 유닛의 체력 멤버 필드에 직접 접근하여 값을 변경한다면 이상한 값(0보다 작거나 100보다 큰 값)을 갖을 수도 있습니다. 이러한 논리적 버그를 방지하려면 유닛을 정의할 때 외부에서 체력 멤버 필드에 직접 접근하는 것을 허용하지 말아야 합니다.

 

이러한 이유로 많은 OOP 언어에서는 멤버의 접근 지정을 설정할 수 있는 키워드(흔히 public, private, protected)를 제공하고 있어요.

 

하지만 Python에서는 멤버의 접근 지정을 설정하는 키워드를 제공하고 있지 않습니다. Python에서 클래스를 정의할 때 멤버 이름에 따라 접근 지정을 설정할 수 있어요.

 

멤버 이름 앞에 언더바(_)가 두 개 붙으면 해당 형식 내부에서만 접근이 가능합니다. 이는 다른 OOP 언어의 private 접근 지정과 같습니다.

 

멤버 이름 앞에 언더바(_)가 한 개 붙으면 해당 형식과 파생 형식에서 접근이 가능합니다. 이는 다른 OOP 언어의 protected 접근 지정과 같습니다. 이 부분은 상속을 다루면서 설명할게요.

 

멤버 이름 앞에 언더바가 없다면 외부에서도 접근이 가능합니다. 이는 다른 OOP 언어의 public 접근 지정과 같습니다.

 

유닛 클래스를 정의하면서 접근 지정에 관해 살펴봅시다.

 

초기화 메서드는 이미 이름이 __init__으로 정해졌으며 개체를 생성할 때 수행합니다. 여기에서는 이름을 입력 인자로 전달받아 이름 멤버 필드에 설정하고 체력 멤버 필드는 100으로 설정하기로 합시다. 메서드를 정의할 때 첫번째 인자로 self 키워드를 명시하면 해당 메서드는 멤버 메서드입니다. 그리고 self는 개체 자신을 의미하며 개체의 멤버에 접근할 때 self 키워드를 이용합니다. 이름 멤버 필드와 체력 멤버 필드는 Unit 클래스 내부에서만 접근할 수 없게 멤버 이름의 시작 부분에 언더바(_)를 명시할게요.

 

만약 def __init__(self, name): 처럼 초기화 메서드를 지정하면 호출할 때는 name부분만 전달하며 self부분은 전달하는 것이 아니라 개체 자신을 의미합니다. 다음은 이름이 “홍길동”인 Unit 개체를 생성하는 코드입니다.

 

만약 외부에서 멤버 필드에 접근할 필요가 있다면 접근자 메서드를 제공하세요. 외부에서 멤버 필드를 설정할 필요가 있다면 설정자 메서드를 제공하세요. 여기에서는 유닛의 체력 멤버 필드와 이름 멤버 필드에 접근하는 접근자는 외부에서 접근할 수 있게 제공하세요.

 

유닛의 체력은 운동하면 늘어나고 술 마시면 줄어들게 할거예요. 이 때 체력은 0에서 100 사이에 있게 조절해 주어야 하는데 체력이 바뀌는 곳마다 이를 조절하는 코드를 작성하는 것은 귀찮을 뿐만 아니라 개발자의 실수로 조절하는 부분을 넣지 않아 버그가 만들어질 수 있어요.

 

되도록이면 멤버 필드 값을 설정하는 부분은 설정자 메서드를 정의하고 멤버 필드 값을 변경하길 원한다면 설정자 메서드를 호출하여 변경하게 구현하세요.

 

다음은 접근 지정을 설명하기 위해 정의한 Unit 클래스와 이를 사용하는 코드입니다.

 

개발 도구에서 Unit 클래스 내부에서는 모든 멤버가 보입니다. 하지만 Unit 클래스 외부에서는 언더바(_)로 시작하는 멤버는 보이지 않습니다.

[그림 1] 접근 지정 확인
[그림 1] 접근 지정 확인