코드로 우주평화

Python _ @property로 getter, setter 구현하기 (feat. 캡슐화) 본문

나는 이렇게 학습한다/Language

Python _ @property로 getter, setter 구현하기 (feat. 캡슐화)

daco2020 2022. 4. 2. 20:11
반응형

캡슐화

파이썬은 클래스를 작성할 때, 변수나 함수 앞에 '__' 를 붙여 캡슐화, 즉 은닉을 할 수 있습니다.

 

예를 들어 객체 내 변수에 접근할 때, 일반적으로 다음처럼 '.'과 변수명만으로 쉽게 접근할 수 있습니다.

class Robot:
    def __init__(self, name, num):
        self.name = name
        self.num = num
        
robot = Robot('다코', '0001')


print(robot.name, robot.num)

'''
결과
>>> 다코 0001
'''

 

 

 

 

하지만 이것은 외부에서 변수를 쉽게 조작할 수 있음을 의미합니다.

 

이를 방지하기 위해 변수앞에 '__'를 붙여 외부에서 접근할 수 없도록 막을 수 있습니다.

 

class Robot:
    def __init__(self, name, num):
        self.__name = name
        self._num = num # _는 __처럼 숨기지는 못하지만 숨긴다고 가정하는 표시이다.
        
robot = Robot('다코', '0001')

print(robot.__name) # 외부에서는 접근할 수 없다.

'''
결과
>>> AttributeError: 'Robot' object has no attribute '__name'
'''

 

 

 

접근하지 못한다면 왜 변수를 할당하냐고 생각할 수 있겠지만, 외부에서 직접 접근하지 못할 뿐 내부에서는 사용 가능합니다. 

 

class Robot:
    def __init__(self, name, num):
        self.__name = name
        self._num = num
    
    def call(self):
        print(f'이름: {self.__name}, 일련번호: {self._num}, 호출합니다.') # 내부 호출

robot = Robot('다코', '0001')

robot.call() # 메서드 호출시에는 변수 사용가능.

'''
결과
>>> 이름: 다코, 일련번호: 0001, 호출합니다.
'''

 

 

이렇듯 중요한 데이터이거나 조심히 다뤄야하는 변수 혹은 함수의 경우 캡슐화를 통해 외부의 접근을 제한할 수 있습니다.

 

하지만 그럼에도 외부의 조작이 필요한 때가 있을 수 있습니다.

그런 경우에는 @property 데코레이터를 사용하여 변수를 가져오거나 수정할 수 있습니다.

 

 

 


 

 

 

@property와 getter

 

우선 @property를 이용해 변수에 접근(getter)하는 방법입니다.

class Robot:
    def __init__(self, name, num):
        self.__name = name
        self._num = num

    @property
    def name(self): # 여기서 함수명은 곧 변수명처럼 다뤄진다.
        return self.__name
    
robot = Robot('다코', '0001')


print(robot.name) 

'''
결과
>>> 다코
'''

'robot.name'이라는 명령으로 name 변수를 불러올 수 있음이 확인됩니다.

여기서 name은 항수명이지만 '()'을 붙이지 않고 마치 변수명을 호출하듯이 사용합니다.

(엄밀히 말하면 '__name'을 직접 불러오는 게 아닌, 함수를 사용해 불러오는 방식입니다.)

 

 

하지만, 접근이 되었다하더라도 name을 외부에서 수정할 수는 없습니다.

이것은 단순히 변수를 호출(getter)한 것에 지나지 않습니다.

# 만약 변수를 외부에서 재할당 한다면 다음과 같은 에러를 만나게 됩니다.

robot.name = '스누피'

'''
결과
>>> AttributeError: can't set attribute
'''

 

 

 


 

 

 

@property와 setter

 

외부에서 변수를 수정해야하는 경우에는 setter를 사용해야 합니다.

class Robot:
    def __init__(self, name, num):
        self.__name = name
        self._num = num

    @property
    def name(self):
        return self.__name
        
    @name.setter
    def name(self, new_name): # 여기서 함수명은 곧 변수명처럼 다뤄진다.
        '''
        ...유효성 검사...
        '''
        self.__name = new_name
        return self.__name
        
robot = Robot('다코', '0001')


print(robot.name) 
robot.name = '스누피' # setter 함수가 호출된 순간이다.
print(robot.name)

'''
결과
>>> 다코
>>> 스누피
'''

 

 setter는 ['@property를 사용한 함수명'.setter] 형태로 사용합니다.

 

위의 코드 robot.name = '스누피'가 동작하는 시점에 setter 함수가 호출되고 변수가 새롭게 할당됩니다.

 

이후 name 호출 시에 '스누피'가 표시됩니다.

 

 

 

 

이제 setter를 활용하여 숨겨진 변수를 외부에서 할당까지 할 수 있게 되었습니다.

그러나 여기서 의문이 들 것입니다.

 

 

이럴 거면 왜 숨기는 거지?

 

 

일반 변수를 사용하면 쉽게 할 수 있는 것을 굳이 어렵게 만든 것처럼 보입니다.

 

 

하지만 setter는 단순히 데이터를 수정하는데 그치지 않습니다.

해당 코드를 다시 보겠습니다.

    @name.setter
    def name(self, new_name):
        '''
        ...유효성 검사...
        '''
        self.__name = new_name
        return self.__name

 

중간에 '유효성 검사'라고 기재되어있습니다.

 

파이썬에서 변수 재할당은 그 내용은 물론 타입까지도 상관없이 재할당 해버립니다.

만약 문자를 할당해야 하는 변수인데 숫자를 할당하면 버그가 생길 겁니다.

 

 

 

하지만 setter는 그러한 문제를 방지할 수 있습니다.

새롭게 들어온 new_name의 변수가 유효한 데이터인지 확인할 수 있는 것입니다.

 

 

setter는 외부에서는 단순히 변수를 호출하는 것처럼 보이지만

그 내부는 함수로 구성되어 있기 때문에 개발자는 함수 내에 코드를 추가할 수 있습니다.

 

    @name.setter
    def name(self, new_name):
    	# new_name이 문자가 아니라면 ValueError
        if not type(new_name) == str:
            raise ValueError
            
        self.__name = new_name
        return self.__name

 

이제 name을 재할당할 때 문자가 아닌 타입이 들어오면 ValueError를 내뱉습니다.

 

이렇듯 개발자는 미리 작성해둔 setter 함수로 객체의 변수를 보다 안전하게 관리할 수 있습니다.

 

 

 

 


 

 

 

정리

- 캡슐화는 내부 변수나 함수를 보다 private 하게 관리하기 위해서 사용합니다.

- 파이썬에서 객체는 내부 변수나 함수 앞에 '__'을 붙여 외부의 접근을 막을 수 있습니다. (캡슐화)

- 외부의 접근을 막았지만 필요한 경우 @property를 사용해 접근할 수 있습니다. (getter)

- 외부에서 수정을 요청할 경우 유효성 및 추가 작업을 수행할 수 있습니다. (setter)

 

 

 

 

레퍼런스

- 타입 파이썬! 올바른 class 사용법과 객체지향 프로그래밍

- 캡슐화 2

 

 

 

반응형