Published on

Python Getter Setter 원리와 장점 5가지 확인하기

Authors

Python Getter Setter 는 객체 지향 프로그래밍에서 사용되는 메서드(함수)로, 객체의 속성(데이터)에 접근하고 수정하는 방식을 제어합니다.

getter와 setter가 무엇이냐면

  • Getter는 클래스의 특정 속성 값을 '가져오는' 메서드입니다. 이는 외부에서 클래스의 속성 값을 직접적으로 액세스하지 않고 안전하게 읽을 수 있게 해줍니다.
  • Setter는 클래스의 특정 속성 값을 '설정하는' 메서드입니다. 이를 통해 속성에 새로운 값이 할당될 때 유효성 검사나 추가적인 처리를 수행할 수 있습니다.

이번 글에서는 python 에서 getter setter를 구현해보고 응용까지 코드와 함께 설명했습니다.

또 왜 getter와 setter를 써야하고, 어떻게 쓰게되는지 장점(특징)을 확인하겠습니다.

1. 기본적인 Getter Setter 와 데코레이터

가장 쉬운 방법은 property 데코레이터를 사용하여 getter와 setter를 정의하는 것입니다.

이 방법은 속성에 직접 접근하는 것처럼 보이지만, 실제로는 메서드를 통해 접근합니다.

기본적으로 구현하는 코드는 아래와 같습니다.

@property 와 @속성명.setter 데코레이터를 사용하는 방법은 아래의 코드와 같습니다.

class Project:
  def __init__(self, name):
    self.__name = name

  @property
  def name(self):
  """
  Getter 구현
  :return:
  """
    return self.__name

  @name.setter
  def name(self, value):
  """
  Setter 구현
  :param value:
  :return:
  """
    self.__name = value

project = Project("기존 프로젝트")

print(project.name)
project.name = "신규 프로젝트"
print(project.name)

출력결과는 다음과 같습니다.

기존 프로젝트
신규 프로젝트

1.1 getter

Getter는 @property 데코레이터를 사용하여 정의합니다.

이렇게 하면 특정 값을 바로 가져올 수 있습니다.

1.2 setter

Setter 는 @속성명.setter 데코레이터를 사용하여 setter 메서드를 명시적으로 정의해야 합니다.

이렇게 하면 해당 속성에 값을 할당할 때 setter 메서드가 호출되어, 값의 할당이 가능해집니다.

1.3 setter 가 없다면? AttributeError: can't set attribute

Python에서 AttributeError: can't set attribute 오류는 클래스에 setter 메서드가 정의되지 않았을 때 발생합니다.

Traceback (most recent call last):
File "somefile~", line xx, in <module>

project.name = "신규 프로젝트"
AttributeError: can't set attribute

클래스에 @property 데코레이터를 사용하여 getter 메서드를 정의하고, 이와 연관된 속성에 값을 할당하려고 할 때 이 오류가 나타납니다.

@property 데코레이터는 속성을 읽기 전용으로 만듭니다. 따라서 해당 속성에 값을 할당하려고 하면 Python 인터프리터는 해당 속성에 대해 setter 메서드가 없다는 것을 인식하고 AttributeError를 발생시킵니다.

2. Setter 구현 방법

데코레이터를 사용하지 않고 Python에서 수동으로 setter 메서드를 구현하는 방법입니다.

Python의 내장 함수인 property()를 사용할 수 있으며, 이 방법은 데코레이터를 사용하는 것보다 더 저수준(low-level)의 접근 방식입니다.

2.1 property() 함수

Python에서 property() 함수는 네 개의 인자를 받을 수 있습니다

fget, fset, fdel, doc. 이들은 각각 속성에 대한 getter, setter, deleter 함수와 문서 문자열을 나타냅니다.

setter를 수동으로 구현하려면 property() 함수에 fgetfset 인자를 제공해야 합니다.

코드는 아래와 같습니다.

class Project:
  def __init__(self, name):
    self.__name = name

  def get_name(self):
    return self.__name

  def set_name(self, value):
    self.__name = value

  # property()를 사용하여 getter와 setter를 설정합니다.
  name = property(get_name, set_name)

project = Project("기존 프로젝트")

print(project.name)
project.name = "신규 프로젝트"
print(project.name)

3. @property와 property()

3.1 객체 속성의 차이

가장 큰 차이라고 한다면 당연하게도, 객체 속성 그 자체라고 할 수 있습니다.

  • 데코레이터를 사용했을 때의 속성은 아래와 같습니다. (오른쪽으로 스크롤 해야 보여집니다.)
['_Project__name', '__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'name']
  • 수동으로 구현했을 때의 속성을 보면 get_name, set_name 등이 보여집니다. (오른쪽으로 스크롤 해야 보여집니다.)
['_Project__name', '__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'get_name', 'name', 'set_name']

3.2 권장

property() 함수를 사용하면, 객체의 속성 접근 방식을 보다 세밀하게 제어할 수 있습니다.

하지만 코드가 간결해지고 가독성이 좋아지기 때문에 데코레이터를 사용하는 방법이 권장됩니다.

4. Getter Setter 와 객체지향 프로그래밍

아래처럼 setter 함수에서 validation 을 할 수 있습니다.

이는 캡슐화와 데이터 무결성을 유지하는데에 중추적인 역할을 하는 것과 마찬 가지입니다.

@name.setter
def name(self, value):
  if not isinstance(value, str):
    raise TypeError("이름은 문자여야 합니다.")
  if len(value) <= 0:
    raise ValueError("이름은 빈 문자열일 수 없습니다.")
  self.__name = value

4.1 Getter Setter 로 얻는 장점 5가지

getter setter를 이용해 프로그래밍 하는 것이 파이써닉한 코드를 구현하고, 객체지향 프로그래밍에 직접연관 된다고 생각합니다.

더불어서 추가적인 로직과 유연성, 확장성은 초기에 프로그래밍을 함에 있어서 설계에 대해 부담을 덜어줍니다.

구현에 초점을 맞추다보면 설계에 느슨해지는 순간이 오는 것 같은데, 그럴 때마다 다시 파이썬의 구조적인 부분을 떠올리면 많은 도움이 되는 것 같습니다.

  • 데이터 무결성(Data Integrity) 유지: setter 메서드를 통해 객체의 상태를 변경할 때 데이터 유효성 검사를 수행할 수 있습니다. 이를 통해 부적절한 데이터 할당을 방지하고 객체의 상태가 항상 유효한 범위 내에 있도록 보장합니다.
  • 캡슐화(Encapsulation) 강화: 객체의 상태(필드 또는 속성)를 직접적으로 변경하는 대신 gettersetter 메서드를 통해 접근합니다. 이는 클래스의 내부 구현을 숨기고 공개 인터페이스만을 제공하여, 객체의 상세 구현을 외부로부터 분리합니다.
  • 추가 로직의 통합: settergetter에 추가적인 로직을 포함시킬 수 있습니다. 예를 들어, setter에서는 값을 설정하기 전에 변환, 로깅, 유효성 검사 등을 수행할 수 있고, getter에서는 요청된 값에 대한 계산 또는 포매팅을 수행할 수 있습니다.
  • 유연성과 확장성: 프로그램이 발전함에 따라 객체의 속성에 대한 접근 방식이나 로직을 변경해야 할 필요가 생길 수 있습니다. gettersetter를 사용하면, 이러한 변경을 클래스 내부에서만 처리하고 클래스를 사용하는 외부 코드는 수정하지 않아도 됩니다.
  • 호환성 유지: 기존의 코드와의 호환성을 유지하면서 클래스의 내부 구현을 변경할 수 있습니다. 예를 들어, 클래스의 내부 데이터 구조가 변경되더라도 gettersetter 인터페이스는 동일하게 유지할 수 있어, 외부 코드에 영향을 주지 않습니다.

hongreat 블로그의 글을 봐주셔서 감사합니다!