본문 바로가기

Python

6-7. 캡슐화와 접근 제한자 개념

파이썬 캡슐화와 접근 제한자 개념

안녕하세요! 지난 시간에는 상속(Inheritance)과 다형성(Polymorphism)을 통해 코드를 재사용하고, 다양한 객체들이 유연하게 동작하도록 만드는 방법을 알아보았습니다. 이제 OOP의 강력한 장점들을 조금씩 느끼고 계실 거예요.

이번 시간에는 객체지향 프로그래밍의 또 다른 중요한 원칙이자, 데이터의 안전성과 코드의 유지보수성을 높이는 데 필수적인 개념인 **캡슐화(Encapsulation)**와 파이썬에서의 접근 제한자(Access Modifiers) 개념에 대해 알아보겠습니다.

캡슐화는 데이터와 그 데이터를 다루는 기능을 하나로 묶고, 외부로부터 데이터를 보호하는 것을 의미합니다. 그럼, 캡슐화가 무엇이고, 파이썬에서 이를 어떻게 구현하는지 함께 살펴볼까요?


Part 1: 캡슐화 (Encapsulation) - 데이터와 기능을 하나로 묶고 보호하기

캡슐화는 객체의 **데이터(속성)**와 그 데이터를 다루는 **기능(메서드)**을 하나의 단위(클래스)로 묶고, 외부에서 객체 내부의 데이터를 직접 접근하거나 조작하는 것을 제한하여 데이터를 보호하는 객체지향의 원칙입니다.

마치 약 캡슐 안에 약 성분(데이터)과 그 성분을 안전하게 보관하는 기술(메서드)을 담아두고, 캡슐 겉면만 보고 사용법을 아는 것처럼, 객체 외부에서는 메서드를 통해 간접적으로만 객체의 상태에 접근하도록 하는 것입니다.

1. 캡슐화의 목적 및 중요성

  • 데이터 보호 및 무결성 유지: 외부에서 객체 내부의 데이터를 함부로 변경하지 못하도록 막아, 데이터가 예상치 못한 상태가 되는 것을 방지합니다. (예: 계좌 잔액을 음수로 직접 설정하는 것 방지)
  • 코드의 응집도 증가: 관련 있는 데이터와 기능을 한 클래스 안에 묶어 관리하므로 코드의 응집도(Cohesion)가 높아집니다.
  • 유지보수 및 확장 용이: 객체 내부 구현이 외부로부터 숨겨지므로, 내부 구현이 변경되어도 외부 코드에는 영향을 미치지 않아 유지보수와 확장이 쉬워집니다.
  • 사용 편의성: 복잡한 내부 로직을 숨기고, 간단한 메서드 호출을 통해 객체를 다룰 수 있게 합니다.

Part 2: 파이썬의 접근 제한자 개념 - 이름 규칙에 따른 약속

다른 객체지향 언어(예: Java의 public, protected, private)와 달리, 파이썬은 변수나 메서드에 대한 엄격한 **접근 제한 키워드(Access Modifier Keywords)**를 제공하지 않습니다. 대신 **이름 규칙(Naming Convention)**을 사용하여 해당 속성이나 메서드가 외부에서 어떻게 사용되기를 '의도'하는지 개발자에게 알려주는 방식을 사용합니다.

파이썬에서는 모든 속성과 메서드가 기본적으로 **공개(Public)**입니다. 하지만 아래와 같은 이름 규칙을 통해 개발자들 간의 약속을 만듭니다.

1. 공개 (Public) 속성/메서드

  • 가장 일반적인 형태입니다. 이름 앞에 특별한 기호가 붙지 않습니다.
  • 클래스 내부와 외부 어디에서든 자유롭게 접근하고 사용할 수 있습니다.
  • 대부분의 속성과 메서드가 이 형태로 정의됩니다.

예시:

Python
 
# 파일 이름: access_public.py

class Product:
    def __init__(self, name, price):
        self.name = name     # 공개 속성
        self.price = price   # 공개 속성

    def get_info(self): # 공개 메서드
        return f"상품명: {self.name}, 가격: {self.price}원"

# 객체 생성
my_product = Product("키보드", 80000)

# 공개 속성에 직접 접근 및 변경 (외부에서 가능)
print(f"상품명: {my_product.name}")
my_product.price = 75000 # 직접 변경 가능
print(f"새로운 가격: {my_product.price}")

# 공개 메서드 호출
print(my_product.get_info())

 

[VS Code 터미널 출력]

파이썬 공개 속성 및 메서드 접근 예시

2. 보호된 (Protected) 속성/메서드 - 단일 밑줄(_)

  • 이름 앞에 **밑줄 하나(_)**를 붙입니다. (예: _protected_attribute, _protected_method())
  • 규칙이 아닌 관례: 파이썬 인터프리터는 이를 특별히 다르게 처리하지 않습니다. 즉, 외부에서 여전히 직접 접근 가능합니다. 하지만 개발자들 사이에서는 "이것은 클래스 내부에서 사용되거나 상속받은 자식 클래스에서만 접근하는 것을 권장한다"는 의미의 약속입니다.
  • 용도: 클래스 내부에서만 사용되거나, 자식 클래스에서 확장/재정의될 가능성이 있는 내부 구현 상세를 나타낼 때 사용됩니다.

예시:

Python
 
# 파일 이름: access_protected.py

class Account:
    def __init__(self, owner, balance):
        self.owner = owner
        self._balance = balance # 보호된 속성 (관례적으로)

    def _update_balance(self, amount): # 보호된 메서드 (관례적으로)
        """내부적으로 잔액을 업데이트하는 메서드"""
        self._balance += amount
        print(f"내부적으로 잔액 업데이트: {self._balance}")

    def deposit(self, amount):
        if amount > 0:
            self._update_balance(amount) # 내부 메서드 호출
            print(f"{amount}원 입금 완료. 현재 잔액: {self._balance}원")
        else:
            print("0원 이상만 입금 가능합니다.")

# 객체 생성
my_account = Account("김은행", 10000)

# 보호된 속성에 외부에서 직접 접근 (가능하지만 권장하지 않음)
print(f"잔액 (직접 접근): {my_account._balance}원")
my_account._balance = 15000 # 직접 변경도 가능 (하지 않는 것이 좋음)
print(f"잔액 (직접 변경 후): {my_account._balance}원")

# 보호된 메서드 외부에서 호출 (가능하지만 권장하지 않음)
my_account._update_balance(2000)
print(f"잔액 (보호된 메서드 호출 후): {my_account._balance}원")

# 공개된 메서드를 통한 정상적인 사용
my_account.deposit(5000)

 

[VS Code 터미널 출력]

파이썬 보호된 속성 및 메서드(_변수) 접근 예시

3. 비공개 (Private) 속성/메서드 - 이중 밑줄(__)

  • 이름 앞에 **밑줄 두 개(__)**를 붙입니다. (예: __private_attribute, __private_method())
  • 이름 맹글링 (Name Mangling): 파이썬 인터프리터는 __로 시작하는 속성이나 메서드 이름을 컴파일 시 자동으로 _클래스이름__원래이름 형태로 변경합니다. (예: __private_attribute는 _ClassName__private_attribute로 변경됨)
  • 용도: 클래스 내부에서만 사용하도록 강력하게 의도된 속성이나 메서드입니다. 외부에서의 직접 접근을 사실상 막는 효과를 줍니다. (완전히 불가능한 것은 아니지만, 직접 접근 시 이름 맹글링된 이름을 사용해야 하므로 어렵습니다.)

예시:

Python
 
# 파일 이름: access_private.py

class User:
    def __init__(self, username, password):
        self.username = username
        self.__password = password # 비공개 속성 (이름 맹글링됨)
        self.__login_attempts = 0 # 비공개 속성

    def __check_password(self, input_password): # 비공개 메서드
        """내부적으로 비밀번호를 확인하는 메서드"""
        if input_password == self.__password:
            self.__login_attempts = 0 # 성공 시 시도 횟수 초기화
            return True
        else:
            self.__login_attempts += 1 # 실패 시 시도 횟수 증가
            return False

    def login(self, input_password): # 공개 메서드 (비공개 메서드 사용)
        if self.__login_attempts >= 3:
            print("로그인 시도 횟수 초과. 계정이 잠겼습니다.")
            return False
        
        if self.__check_password(input_password): # 비공개 메서드 호출
            print(f"{self.username}님, 로그인 성공!")
            return True
        else:
            print(f"로그인 실패: 비밀번호가 틀렸습니다. (시도 횟수: {self.__login_attempts})")
            return False

# 객체 생성
my_user = User("coder_kim", "mysecretpass")

# 비공개 속성/메서드에 외부에서 직접 접근 시도 (오류 발생!)
# print(my_user.__password) # AttributeError: 'User' object has no attribute '__password'
# my_user.__check_password("wrongpass") # AttributeError

# 이름 맹글링된 이름으로 접근 시도 (가능은 하나 권장하지 않음, 내부 구현에 의존)
# print(my_user._User__password) # 직접 접근 가능 (하지만 이렇게 하지 마세요!)

# 공개된 메서드를 통한 정상적인 사용
my_user.login("wrongpass")
my_user.login("wrongpass")
my_user.login("wrongpass") # 3회 실패
my_user.login("mysecretpass") # 계정 잠김 메시지 출력

print("\n--- 정상 로그인 시도 ---")
my_user2 = User("new_user", "1234")
my_user2.login("1234")

 

[VS Code 터미널 출력]

파이썬 비공개 속성 및 메서드(__변수) 접근 예시 및 이름 맹글링

Part 3: 캡슐화 구현 요약

파이썬에서 캡슐화는 주로 다음과 같은 방식으로 구현됩니다.

  1. 속성 숨기기:
    • 중요한 데이터(속성)를 비공개(__변수)로 정의하여 외부에서 직접 접근을 어렵게 합니다.
  2. 게터(Getter)와 세터(Setter) 메서드 사용:
    • 비공개 속성에 접근하거나 값을 변경해야 할 경우, get_속성명() (게터) 또는 set_속성명(value) (세터)와 같은 공개(Public) 메서드를 정의하여 간접적으로 접근하도록 합니다.
    • 이를 통해 데이터에 대한 유효성 검사, 로깅 등 추가적인 로직을 삽입할 수 있어 데이터 무결성을 높입니다. (다음 포스팅에서 더 자세히 다룰 예정입니다.)

예시: 간단한 게터/세터

Python
 
# 파일 이름: encapsulation_getter_setter.py

class Temperature:
    def __init__(self, celsius):
        self.__celsius = celsius # 비공개 속성

    # 게터 메서드 (온도 가져오기)
    def get_celsius(self):
        return self.__celsius

    # 세터 메서드 (온도 설정)
    def set_celsius(self, value):
        if not isinstance(value, (int, float)):
            raise TypeError("온도는 숫자여야 합니다.")
        if value < -273.15: # 절대 0도 이하 불가
            raise ValueError("온도는 절대 0도(-273.15) 이상이어야 합니다.")
        self.__celsius = value
        print(f"온도가 {self.__celsius}도로 설정되었습니다.")

# 객체 생성
temp = Temperature(25)

# 게터로 값 가져오기
print(f"현재 온도: {temp.get_celsius()}도")

# 세터로 값 설정 (유효성 검사 포함)
try:
    temp.set_celsius(30)
    temp.set_celsius(-300) # 오류 발생 시도
except (TypeError, ValueError) as e:
    print(f"오류: {e}")

# 직접 접근 시도 (오류 발생)
# print(temp.__celsius) # AttributeError

 

[VS Code 터미널 출력]

파이썬 캡슐화 구현 (게터/세터) 예시

마무리하며

이번 시간에는 객체지향 프로그래밍의 중요한 원칙인 **캡슐화(Encapsulation)**와 파이썬에서 이를 구현하는 **접근 제한자 개념(이름 규칙)**에 대해 알아보았습니다.

  • 캡슐화: 데이터와 기능을 묶고 외부로부터 데이터를 보호하는 것.
  • 접근 제한자: 파이썬은 엄격한 키워드 대신 이름 앞의 밑줄(_, __)을 통해 속성/메서드의 의도된 접근 수준(공개, 보호된, 비공개)을 나타냅니다.
    • _변수: 보호된 (Protected) - 외부 접근 가능하지만, 내부 사용 권장 (관례)
    • __변수: 비공개 (Private) - 이름 맹글링을 통해 외부 직접 접근 어렵게 만듦 (강력한 내부 사용 권장)

캡슐화를 통해 데이터의 무결성을 높이고, 코드를 더욱 안정적이고 유지보수하기 쉽게 만들 수 있습니다.

다음 포스팅에서는 클래스와 OOP의 고급 개념인 **추상 클래스(Abstract Class)**와 **인터페이스(Interface)**에 대해 알아보겠습니다.


궁금한 점이 있다면 언제든지 질문해주세요! 다음 포스팅에서 만나요!

반응형