Computer >> 컴퓨터 >  >> 프로그래밍 >> Python

파이썬 클래스의 비공개 변수(Private Variables) 완벽 가이드

이 튜토리얼에서는 파이썬 클래스(class)비공개 변수(private variables)에 대해 자세히 살펴보겠습니다.

파이썬에는 진짜 '비공개 변수'가 없습니다

C++나 Java 같은 언어와 달리, 파이썬에는 엄격한 의미의 비공개 변수 개념이 존재하지 않습니다. 대신 대부분의 파이썬 개발자는 네이밍 컨벤션(naming convention)을 활용해 "이 변수는 공개용이 아니라 내부 전용"이라는 사실을 표시합니다.

그 방법이 바로 변수 이름 앞에 더블 언더스코어(double underscore, __)를 붙이는 것입니다. 예를 들어 __one, __two처럼 이름을 지으면 비공개 변수로 간주합니다(물론 진짜 비공개는 아닙니다).

즉, 더블 언더스코어로 시작하는 변수라고 해서 접근이 완전히 차단되는 것은 아닙니다. 먼저 비공개 스타일의 변수를 만드는 방법을 살펴본 후, 이 변수에 접근하는 방법까지 순서대로 알아보겠습니다.

비공개 변수 생성 예제

# 클래스 정의
class Sample:
    def __init__(self, nv, pv):
        # 일반 변수
        self.nv = nv
        # 비공개 변수(엄밀히 말하면 아님)
        self.__pv = pv

# Sample 클래스의 인스턴스 생성
sample = Sample('Normal variable', 'Private variable')

위 코드에서는 클래스 하나와 그 인스턴스를 만들었고, __init__ 메서드 안에 일반 변수(nv)와 비공개 변수(__pv) 두 가지를 정의했습니다. 이제 이 변수들에 접근해 보면 어떤 일이 일어나는지 확인해 보겠습니다.

일반적인 방식으로 접근하면 오류가 발생한다

# 클래스 정의
class Sample:
    def __init__(self, nv, pv):
        # 일반 변수
        self.nv = nv
        # 비공개 변수(엄밀히 말하면 아님)
        self.__pv = pv

# Sample 클래스의 인스턴스 생성
sample = Sample('Normal variable', 'Private variable')

# nv 변수 접근
print(sample.nv)
# __pv 변수 접근
print(sample.__pv)

실행 결과

위 코드를 실행하면 다음과 같은 결과가 출력됩니다.

Normal variable
---------------------------------------------------------------------------
AttributeError                             Traceback (most recent call last)
<ipython-input-13-bc324b2d20ef> in <module>
     14
     15 # __pv 변수 접근
---> 16 print(sample.__pv)
AttributeError: 'Sample' object has no attribute '__pv'

nv 변수는 아무 문제 없이 출력되었지만, __pv 변수에 접근하는 순간 AttributeError가 발생했습니다.

왜 이런 오류가 생길까요? 객체에 __pv라는 이름의 속성(attribute)이 존재하지 않기 때문입니다. 그렇다면 __init__ 메서드 안의 self.__pv = pv 구문은 어디로 간 걸까요? 이 부분은 잠시 후에 다루고, 우선 __pv 변수에 접근하는 올바른 방법부터 살펴보겠습니다.

네임 맹글링(Name Mangling)과 올바른 접근 방법

더블 언더스코어로 시작하는 클래스 변수는 _클래스명__변수명(_className__variableName) 형태로 접근할 수 있습니다. 따라서 위 예제에서는 _Sample__pv라는 이름으로 접근하면 됩니다.

# 클래스 정의
class Sample:
    def __init__(self, nv, pv):
        # 일반 변수
        self.nv = nv
        # 비공개 변수(엄밀히 말하면 아님)
        self.__pv = pv

# Sample 클래스의 인스턴스 생성
sample = Sample('Normal variable', 'Private variable')

# nv 변수 접근
print(sample.nv)
# _Sample__pv 이름으로 __pv 변수 접근
print(sample._Sample__pv)

실행 결과

Normal variable
Private variable

이번에는 오류 없이 두 변수 모두 정상적으로 출력되었습니다. 그런데 왜 __pv라는 변수 이름이 바뀐 걸까요?

파이썬에는 네임 맹글링(name mangling)이라는 개념이 있습니다. 파이썬은 더블 언더스코어로 시작하는 변수들의 이름을 자동으로 변경하는데, 클래스 변수의 이름이 더블 언더스코어로 시작하면 _클래스명__변수명 형태로 변환됩니다. 그래서 sample.__pv로는 접근할 수 없고 sample._Sample__pv로만 접근이 가능한 것입니다.

메서드에도 적용되는 네임 맹글링

이 네임 맹글링 규칙은 변수뿐 아니라 클래스의 메서드(method)에도 동일하게 적용됩니다. 다음 코드로 직접 확인해 볼 수 있습니다.

class Sample:
    def __init__(self, a):
        self.a = a

    # 비공개 메서드(엄밀히 말하면 아님)
    def __get_a(self):
        return self.a

# Sample 클래스의 인스턴스 생성
sample = Sample(5)

# 올바른 이름으로 메서드 호출
print(sample._Sample__get_a())
# 잘못된 이름으로 메서드 호출
print(sample.__get_a())

실행 결과

5
---------------------------------------------------------------------------
AttributeError                             Traceback (most recent call last)
<ipython-input-19-55650c4990c8> in <module>
     14
     15 # 잘못된 이름으로 메서드 호출
---> 16 print(sample.__get_a())
AttributeError: 'Sample' object has no attribute '__get_a'

네임 맹글링이 적용된 실제 이름인 _Sample__get_a()로 호출하면 정상적으로 값이 반환되지만, __get_a()라는 원래 이름으로 호출하면 AttributeError가 발생하는 것을 확인할 수 있습니다.

마무리

정리하면, 더블 언더스코어를 사용하는 목적은 변수나 메서드에 대한 외부 접근을 강제로 차단하기 위함이 아닙니다. "이 변수나 메서드는 클래스 내부에서만 사용하도록 의도된 것"이라는 사실을 다른 개발자에게 알려주는 약속(컨벤션)에 가깝습니다. 파이썬 커뮤니티의 "우리는 모두 어른이다(We are all consenting adults here)"라는 철학이 이러한 설계에 반영된 결과이기도 합니다.

튜토리얼을 읽으면서 궁금한 점이 있다면 댓글로 남겨주세요.