개념소개: 캡슐화는 객체지향 프로그램에서 가장 중요한 기능 중 하나이다. 이는 특정 데이터와 이 데이터를 이용해 동작하는 메소드를 한 데 묶는 기능을 의미하며, 이를 통해 사용자가 변수와 메소드에 직접적으로 접근하여 실수/고의로 데이터를 변경하는 행위를 미연에 방지해준다.우리가 흔히 사용하는 데이터와 함수를 내포하는 '클래스'가 바로 이 캡슐화의 한 예라고 할 수 있다.
사용이유 예시: 회사를 예로 들어 설명하자면, 한 회사에 판매, 총무, 경영 등 다양한 부서가 있고 각 부서마다 자신이 처리하는 데이터 정보가 다르다. 만일 판매측에서 총무가 보유하고 있는 데이터에 임의로 접근을 하여 이를 마음대로 가져오거나, 수정하려고 하면 회사 전체에 큰 혼란을 야기할 것이다. 이렇게 데이터에 대한 접근과 수정을 위해선 총무측 담당자에게 직접 연락해서 데이터 사용에 대한 관련 중요 정보를 직접듣고 협의하는 시간을 거쳐야만 할 것이다.
=> 캡슐화도 프로그래밍 측면에서, 다른 개발자가 너무 쉽게 데이터에 접근해서 실수 또는 고의로 데이터를 변경하는 불상사를 막기위해, 그리고 코드 작성자의 의도를 추후에 읽어볼 타인을 위해 더 확실하게 하기 위해 경계병을 세워 놓은 것이다.
캡슐화 종류: 파이썬은 자바의 '접근제한자(Private)' 설정 처럼 완벽한 외부 접근을 통제하는 기능이 내재 되어 있지 않는다. 따라서 이에 비록 못미치지만 파이썬에서 나름 방어장치를 설치해 볼 수 있다. 파이썬에서의 캡슐화는 크게 1. Private Variable 개념을 이용 하는 방법과, (어떤 한 객체 변수를 다른 한 객체의 메소드를 이용해야지만 변경할 수 있게 하는 방법), 2. Protected members 개념을 이용하는 방법 (클래스 외부에서 접근이 불가하고 해당 클래스 내부나 하위 클래스에서만 접근이 가능한 방법) 크게 이 두 가지로 나뉜다. 더 자세한 내용은 아래로...
어떤 한 객체 변수를 다른 한 객체의 메소드를 이용해야지만 변경할 수 있게 하는 방법이다. 변수명앞에 언더스코어 __ 를 이와 같이 두개 붙여주면 된다. 흔히들 'name mangling' (이름 장식) 기법으로도 통칭된다.
Private Variable은 대게 실수에서 비롯된 오류를 방지하고자 설정해놓은 간이 장치이다. 사용자가 정 원한다면 의도적으로 해당 변수에 접근해서 데이터를 변경하는 것이 가능하기 때문에, 아예 접근 불가능한 것이 아니라 접근할 수 있는 변수의 이름이 달라지는 것(mangling)이라고 이해할 수 있다. 참고로, 이 기법은 디버거 사용을 위해 꽤 유용하게 쓸 수 있다.
<Private Variables 코드예제(1): 변수 접근 불가>
class Example():
def __init__(self, name):
self.__name = name
call = Example('Ray')
print(call.__name)
출력결과:
AttributeError: 'Example' object has no attribute '__name'
<Private Variables 코드예제(2): Private 변수 접근/수정의 올바른 예>
class Example():
def __init__(self, name):
self.__name = name
def update_name(self, name): #name 변경 메소드 선언
self.__name = name #name 값 변경
def get_name(self): #name 값 반환 메소드 선언
print(self.__name) #name 값 출력
call = Example('Ray')
call.get_name()
call.update_name('Kim')
call.get_name()
출력결과:
Ray
Kim
클래스 외부에서 접근이 불가하고 해당 클래스 내부 하위 클래스에서만 접근하게끔 설정하는 기법이다. 두 개를 붙인 Private Variable과는 달리, 변수명 앞에 언더스코어 _ 를 하나 붙이면 된다.
<Protected Members 코드예제>
# Base Class 생성
class Base:
def __init__(self):
# Protected member 표현
self._number1 = 1
# Derived Class 생성
class Derived(Base):
def __init__(self):
# Base Class 생성자 호출
Base.__init__(self)
print("Calling protected member of base class: ")
print(self._number1)
obj1 = Derived()
obj2 = Base()
print(obj2.number1)
출력결과:
Calling protected member of base class:
1
AttributeError: 'Base' object has no attribute 'number1'