객체의 내부 상태를 외부에서 마음대로 변경할 수 있다면, 코드의 안정성과 유지보수성이 크게 떨어질 수 있다. 예를 들어, 집을 짓는다고 생각해 보자. 만약 집의 벽이나 지붕을 아무나 마음대로 변경할 수 있다면, 구조적인 안전성이 확보되지 않을 것이다. 이와 마찬가지로, 객체 지향 프로그래밍(OOP)에서도 객체의 내부 데이터를 보호하고, 안전하게 관리하는 방법이 필요합니다. 바로 정보 은닉(Information Hiding)이다. 이번 글에서는 파이썬에서 정보 은닉이 무엇인지, 왜 중요한지, 그리고 어떻게 구현하는지에 대해 알아보도록 하자.
마음대로 인스턴스 변수의 값을 변경할 수 있다면?
객체의 인스턴스 변수는 객체의 상태를 나타내는 중요한 데이터이다. 만약 이러한 변수를 외부에서 자유롭게 변경할 수 있다면, 문제점이 발생할 수 있다. 어떤 서비스의 유저를 나타내는 User 클래스를 살펴보자.
class User:
def __init__(self, name, age):
self.name = name
self.age = age
# 객체 생성
user = User("홍길동", 25)
# 외부에서 인스턴스 변수 직접 수정
user.age = -5 # 논리적으로 맞지 않는 나이
print(user.age) # -5
위 코드에서 객체 user의 변수 age에 마음대로 접근하여 값을 변경할 수 있다. 하지만 age가 음수가 될 수 있다는 것은 논리적으로 맞지 않고, 이렇게 되면 프로그램의 신뢰성을 떨어뜨린다.
마음대로 인스턴스 변수의 값이 변경될 수 있는 상황에서는 여러 문제가 발생할 수 있다. 정리해 보면 다음과 같다:
- 데이터 무결성 저하: 외부에서 임의로 값을 변경하면, 객체의 상태가 예상치 못한 방식으로 변할 수 있다.
- 디버깅 어려움: 값이 언제, 어디서 변경되었는지 추적하기 어려워져 버그를 찾기 힘들어진다.
- 코드 유지보수성 저하: 객체의 내부 구조가 외부에 노출되면, 객체를 수정할 때 외부 코드도 함께 수정해야 하는 번거로움이 생긴다.
정보 은닉이란?
정보 은닉(Information Hiding)은 객체 지향 프로그래밍에서 구현 세부 사항을 클래스 안에 감추고 외부에는 숨기는 것이다. 그렇게 함으로써 필요한 인터페이스만을 제공한다. 정보 은닉은 객체의 내부 데이터가 외부에 의해 임의로 변경되는 것을 방지하고, 객체의 무결성을 유지할 수 있게 해 준다.
이러한 정보 은닉을 구현하려면 클래스 안에 변수를 선언할 때 private 한 변수로 만들면 된다. 그러면 외부로부터의 접근이 차단된다.
인스턴스 변수를 private으로 정의하려면 변수 이름 앞에 언더스코어 두 개 '__'를 붙이면 된다. 이렇게 선언된 인스턴스 변수는 클래스 내부에서만 접근할 수 있다. 이렇게 선언된 인스턴스 변수들은 클래스 바깥에서 접근하려고 하면 오류가 난다.
class User:
def __init__(self, name, age):
self.__name = name # private
self.__age = age # private
user = User()
print(user.__name) # ❌ 에러 발생 AttributeError
정보 은닉의 장점
클래스의 멤버에 대한 접근을 제어하는 것은 객체지향 프로그래밍의 핵심적인 부분이다. 위에서 살펴본 예제의 방법처럼 정보 은닉을 구현해서 클래스를 구현하면 여러 장점이 있다.
- 데이터 보호: 객체의 내부 상태를 외부에서 변경할 수 없으므로 데이터 값이 부적절한 값으로 변경되는 것을 막을 수 있다.
- 유지보수성 향상: 내부 구현을 숨김으로써, 객체의 내부 구조를 변경해도 외부 코드는 영향을 받지 않는다.
- 코드의 명확성: 필요한 인터페이스만 제공함으로써, 객체의 사용법이 명확해진다.
- 재사용성 증가: 안정된 인터페이스를 제공하여, 객체를 다양한 상황에서 재사용할 수 있다.
접근자(getter)와 설정자(setter)
정보 은닉을 구현한 private 변수들은 클래스 내부로 다 숨겨졌다. 그런데 이 변수들이 외부에서 필요한 경우에는 어떻게 하면 좋을까?
정보 은닉을 구현하면서도 객체의 데이터를 안전하게 접근하고 수정하려면 접근자(getter)와 설정자(setter) 메서드를 사용하면 된다. 접근자 메서드는 인스턴스 변숫값을 반환하고 설정자 메서드는 인스턴스 변수값을 설정하는 역할을 한다. 이런 메서드의 이름은 보통 get이나 set이 메서드 이름을 앞에 붙여서 사용한다.
class User:
def __init__(self, name, age):
self.__name = name
self.__age = age
def get_age(self): # 접근자
return self.__age
def set_age(self, age): # 설정자
if age >= 0:
self.__age = age
else:
print("나이는 음수가 될 수 없습니다.")
위의 예제처럼 설정자는 나이가 양수인지를 검사하는 등의 데이터의 유효성을 검사하거나, 데이터 변경 시에 추가적인 작업을 수행하도록 할 수도 있다.
이제 접근자와 설정자 메서드를 통해 age 값에 접근하고 age 값을 변경할 수 있다.
user = User("홍길동", 25)
# 접근자를 통해 나이 확인
print(user.get_age()) # 25
# 설정자를 통해 나이 변경
user.set_age(30)
print(user.get_age()) # 30
# 잘못된 나이 설정 시도
user.set_age(-5) # 나이는 음수가 될 수 없습니다.
print(user.get_age()) # 30
접근자와 설정자는 왜 사용할까?
아니 그런데 왜 이렇게 귀찮게 굳이 접근자와 설정자를 사용해야 하는 걸까? 그냥 user.age = 30와 같이 바로 접근할 수 있도록 하면 새로 메서드를 정의할 필요도 없고 시간도 절약될 것 같은데 말이다.
그럼에도 불구하고 접근자와 설정자를 사용하는 이유는 단순히 값을 할당하는 것 이상의 이점을 제공하기 때문입니다. 그 이유를 정리해 보면 다음과 같다:
- 접근자와 설정자를 사용해야만 나중에 클래스를 업그레이드할 때 편하다.
- 접근자에서 매개변수를 통하여 잘못된 값이 넘어오는 경우, 이를 사전에 차단할 수 있다.
- 필요할 때마다 인스턴스 변숫값을 계산하여 반환할 수 있다.
- 접근자만을 제공하면 자동적으로 읽기만 가능한 인스턴스 변수를 만들 수 있다.
정리
정보 은닉은 객체 지향 프로그래밍에서 객체의 내부 데이터를 보호하고, 안정적인 인터페이스를 제공하는 중요한 원칙이다. 파이썬에서는 언더스코어를 활용한 접근 제한과 접근자, 설정자 메서드를 통해 효과적으로 정보 은닉을 구현할 수 있다. 이를 통해 코드의 안정성, 유지보수성, 재사용성을 높일 수 있으며, 더 나아가 깨끗하고 효율적인 코드 작성을 도와준다.
'Language > Python' 카테고리의 다른 글
[Python] 파이썬 연산자 오버로딩 이해하기 (0) | 2025.01.22 |
---|---|
[Python] 파이썬 클래스 변수 이해하기 (클래스 변수 vs 인스턴스 변수) (0) | 2025.01.22 |
[Python] 파이썬 클래스와 생성자 사용하여 객체 생성하기 (0) | 2025.01.21 |
[Python] 객체지향 프로그래밍(OOP) 이해하기 (1) | 2025.01.20 |
[Python] 파이썬의 언패킹 연산자 (0) | 2025.01.20 |