Programming Language/Python

Getter/Setter를 파이써닉하게 구현하기(@property)

devsean 2025. 4. 19. 21:31

캡슐화와 Getter/Setter

객체 지향 프로그래밍의 관점에서, 객체의 필드가 외부에 노출되는 것은 적절하지 않다. 어떤 필드는 외부에 노출되거나 값이 변경되어서는 안되는데, 필드가 외부에 노출되어 직접 접근할 수 있다면 그러한 제약 사항이 위반될 것이다. 그러므로 일반적으로 필드를 감추고, 접근하거나(Getter) 수정하는(Setter) 메서드를 만들어서 외부에 노출시킨다. 그렇게 함으로써 어떤 객체의 필드를 일관된 방법으로 접근하고 수정할 수 있도록 제약할 수 있다.

 

get_name, set_name

Python의 네이밍 컨벤션에 맞추어, 흔히 Java에서 사용하듯 Getter와 Setter를 구현할 수 있다.

class Duck():
    def __init__(self, input_name):
        # 네임 맹글링 : private 속성으로 만들어주어, 외부에서 직접 접근 불가
        self.__name = input_name
    def get_name(self):
        print("inside the getter", self.__name)
        return self.__name
    def set_name(self, input_name):
        print("inside the setter")
        self.__name = input_name

if __name__ == "__main__":
    duck = Duck("Donald")
    duck.get_name() 
    duck.set_name("Donna")
    duck.get_name()

 

파이써닉한 방법 : 좀 더 간결하게 만들기

그러나 이는 파이써닉한 방법이 아니다. 파이썬의 철학에 따르면 코드는 간결하고 읽기 쉬워야 한다. 그러므로 필드에 직접 접근하거나 수정하는 것처럼 동작하게끔 하는 것이 더 좋을 것이다. 참고로 파이썬의 철학이 궁금하다면, 인터프리터 창에서 다음 명령어를 통해 확인할 수 있다.

>>> import this
The Zen of Python, by Tim Peters

Beautiful is better than ugly.
Explicit is better than implicit.
Simple is better than complex.
Complex is better than complicated.
Flat is better than nested.
Sparse is better than dense.
Readability counts.
....

 

property

property라는 함수를 이용해서 getter와 setter를 만들 수 있다. get_name과 set_name 함수를 만들고, 그 밑에 property로 해당 함수를 지정해주면, 선언한 변수명을 따르게 된다.

class Duck():
    def __init__(self, input_name):
        # 네임 맹글링 : private 속성으로 만들어주어, 외부에서 접근 불가
        self.__hidden_name = input_name
    def get_name(self):
        print("inside the getter", self.__hidden_name)
        return self.__hidden_name
    def set_name(self, input_name):
        print("inside the setter")
        self.__hidden_name = input_name

    # Getter/Setter 설정하기 1
    # property를 선언하면 다음과 같이 name_property로 접근 가능해짐
    # 선언한 변수명을 따르며, 원래 변수명과 다르게 만들 수 있음
    name_property = property(get_name, set_name)


if __name__=="__main__":
    don = Duck('Donald')
    don.name_property
    don.name_property = 'Donna'
    don.name_property

 

@property

좀 더 간결하게 만들기 위해 데커레이터를 활용할 수 있다. 다음과 같이, get_name과 set_name 메서드를 추가로 만들지 않아도 된다.

class Duck():
    def __init__(self, input_name):
        # 네임 맹글링 : private 속성으로 만들어주어, 외부에서 접근 불가
        self.__hidden_name = input_name
    
    # Getter/Setter 설정하기 2
    # 다음과 같이 데커레이터를 붙일 수 있음
    # @property에 선언한 함수명을 따름
    @property
    def name_decorator(self):
        print("inside the getter", self.__hidden_name)
        return self.__hidden_name
    
    @name_decorator.setter
    def name_decorator(self, input_name):
        print("inside the setter")
        self.__hidden_name = input_name
        
if __name__=="__main__":
    don = Duck('Donald')
    don.name_decorator
    don.name_decorator = 'Donna'
    don.name_decorator

 

추가로, 다음과 같이 기존 필드의 값을 변형하여 새로운 필드를 만들어낼 수도 있다. 그리고 setter를 붙이지 않으면 읽기 전용 필드임을 명시할 수 있다.

# @property는 계산된 값의 속성도 참조할 수 있음
# Setter를 명시하지 않는다면, 읽기 전용 필드
class Circle():
    def __init__(self, radius):
        self.radius = radius

    @property
    def diameter(self):
        return 2 * self.radius

if __name__=="__main__":
    c = Circle(radius=3)
    print(c.diameter)

 

장점과 객체 지향 관점에서의 한계점

코드가 한결 간결하고, 읽기 쉬워진다. 굳이 메서드를 호출하지 않고도 필드에 직접 접근하듯이 코딩이 가능해진다. @property를 통해 외부에서 접근 및 수정할 속성을 명시할 수도 있다.

 

한편 (@property에 대한 것은 아니지만) 캡슐화의 관점에서 파이썬은 한계를 가진다. 파이썬의 네임 맹글링(던더, __)는 자바의 private과 같이 필드를 외부에서 아예 접근이 불가능하도록 막는 것은 아니다. 이는 '동의 성인' 정책을 채택하여 개발자에게 자유도를 부여하는 시도이지만, 강제성의 관점에서는 엄격하지 못해 사이드 이펙트를 초래할 수도 있다. 파이썬은 객체 지향 프로그래밍을 지원하는 언어이지, 그것을 강제하는 언어는 아니라는 점을 알 수 있다.

class Duck:
    def __init__(self):
        self.__hidden_name = "Donald"

if __name__ == "__main__":
    duck = Duck()
    print(duck._Duck__hidden_name) # dir(duck)으로 확인 가능

 

참고 자료

처음 시작하는 파이썬 2판 10장 객체 (빌 루바노빅, 2020)

 

'Programming Language > Python' 카테고리의 다른 글

Python을 활용한 비동기 처리(Asyncio, Coroutine)  (0) 2026.01.06
Python ORM : SQLAlchemy  (2) 2025.05.03