오늘은 프라이빗 변수와 게터/세터에 대해 알아보겠다.
객체 지향 프로그래밍의 최종 목표는 객체를 효율적으로 만들고 사용하는 것이다.
객체를 효율적으로 사용한다는 것은 어떤 말일까?
# 원의 둘레와 넓이를 구하는 객체 지향 프로그램
import math
class Circle:
def __init__(self, radius):
self.radius = radius
def get_circumference(self):
return 2 * math.pi * self.radius
def get_area(self):
return math.pi * (self.radius ** 2)
# 원의 둘레와 넓이를 구합니다.
circle = Circle(10)
print("원의 둘레: {:.3f}".format(circle.get_circumference()))
print("원의 넓이: {:.3f}".format(circle.get_area()))
위 코드를 살펴보자.
원의 둘레와 넓이를 구하는 객체 지향 프로그램을 만들어 보았다.
class 로 Circle 클래스를 선언하고, 각 기능들을 삽입했다.
실행결과도 잘 나온다.
근데, Circle 클래스의 radius 속성에 음수를 넣으면 어떻게 될까?
계산이 잘 된다!...가 아니라.
원의 넓이는 제곱해서 괜찮지만, 둘레는 음수가 나온다.
생각해보자. 현실에서는 길이가 음수가 나올 수 있는가? 그럴 수 없다.
따라서 길이를 음수로 넣는 것을 막는 방법이 필요하다.
프라이빗 변수
일단 변수를 마음대로 사용하는 것을 막아야 한다.
파이썬은 내부의 변수를 외부에서 사용하는 것을 막고 싶을 때 인스턴스 변수 이름을 __<변수이름> 형태로 선언한다. 언더 바 2개다.
# 프라이빗 변수
import math
class Circle:
def __init__(self, radius):
self.__radius = radius
def get_circumference(self):
return 2 * math.pi * self.__radius
def get_area(self):
return math.pi * (self.__radius ** 2)
# 원의 둘레와 넓이를 구합니다.
circle = Circle(10)
print("원의 둘레: {:.3f}".format(circle.get_circumference()))
print("원의 넓이: {:.3f}".format(circle.get_area()))
# __radius에 접근합니다.
print("# __radius에 접근합니다.")
print(circle.__radius)
위 코드를 살펴보자.
radius를 프라이빗 변수로 선언하여 사용하고 있다.
둘레와 넓이는 문제가 없으니 출력이 된다.
하지만, 뒤쪽에 radius에 접근하는 코드는 예외가 뜨기 마련이다.
왜냐? radius를 프라이빗 변수로 선언했으니 외부에서 접근할 수 없기 때문이다.
게터와 세터
그런데 중간에 원의 둘레를 변경하고 싶다면 어쩔까? 변경도 못하고 시무룩하게 있을 순 없지 않은가..
클래스 외부에서 직접 접근할 수 없기 때문에, 간접적으로 접근할 수 있는 방법이 필요하다.
그때 사용하는게 게터와 세터이다.
게터와 세터는 프라이빗 변수의 값을 추출하거나 변경할 목적으로, 간접적으로 속성에 접근 할 수 있도록 해주는 함수이다.
# 게터와 세터
import math
class Circle:
def __init__(self, radius):
self.__radius = radius
def get_circumference(self):
return 2 * math.pi * self.__radius
def get_area(self):
return math.pi * (self.__radius ** 2)
# 게터와 세터를 선언합니다.
def get_radius(self):
return self.__radius
def set_radius(self, value):
self.__radius = value
circle = Circle(10)
print("원의 둘레: {:.3f}".format(circle.get_circumference()))
print("원의 넓이: {:.3f}".format(circle.get_area()))
print()
# 간접적으로 __radius에 접근합니다.
print("# __radius에 접근합니다.")
print(circle.get_radius())
print()
# 원의 둘레와 넓이를 구합니다.
circle.set_radius(2)
print("# 반지름을 변경하고 원의 둘레와 넓이를 구합니다.")
print("원의 둘레: {:.3f}".format(circle.get_circumference()))
print("원의 넓이: {:.3f}".format(circle.get_area()))
위 코드를 살펴보자.
Circle 클래스 안에 get_radius 와 set_radius 두개의 함수가 생성되었다.
각 기능은 get에서는 radius의 값을 리턴, set에서는 radius의 값을 value의 매개변수로 변경 이다.
초반에 원래 원의 둘레, 넓이를 구하고 radius의 값을 리턴하는 출력을 보았다.
그리고 두번째 실행결과에서는 set_radius로 수를 변경하고 출력했다. 결과가 달라졌다.
이렇게 함수를 사용해 값을 변경하면 여러 가지 처리를 추가할 수 있다.
이런 방법으로 아까 음수로 입력된 수를 방지하는 코드도 짤 수가 있다.
# 게터 세터로 변수를 안전하게 사용하기
def set_radius(self, value):
if value <= 0:
raise TypeError("길이는 양의 숫자여야 합니다.")
self.__radius = value
이렇게 짠다면 0 이하의 숫자에 방지를 할 수 있을 것이다.
테코레이터를 사용한 게터와 세터
게터와 세터를 함수로 만드는 일이 많아져서 파이썬에서는 게터와 세터를 쉽게 만들고 사용할 수 있게 하는 기능을 제공한다.
# 데코레이터를 사용해 게터와 세터 만들기
import math
class Circle:
def __init__(self, radius):
self.__radius = radius
def get_circumference(self):
return 2 * math.pi * self.__radius
def get_area(self):
return math.pi * (self.__radius ** 2)
@property
def radius(self):
return self.__radius
@radius.setter
def radius(self, value):
if value <= 0:
raise TypeError("길이는 양의 숫자여야 합니다.")
self.__radius = value
print("# 데코레이터를 사용한 Getter와 Setter")
circle = Circle(10)
print("원래 원의 반지름:", circle.radius)
circle.radius = 2
print("변경된 원의 반지름:", circle.radius)
print()
# 강제로 예외를 발생시킵니다.
print("# 강제로 예외를 발생시킵니다.")
circle.radius = -10
위 코드를 살펴보자.
변수 이름과 같은 함수를 정의 하고, 위에 @property와 @<변수 이름>.setter라는 데코레이터를 붙여주면 된다.
이렇게 하면 circle.radius를 사용하는 것만으로 자동으로 게터와 세터가 호출되도록 할 수 있다.
오늘은 프라이빗 변수와 게터/세터를 공부해보았다.
위 개념들은 어느 언어를 가든간에 있는 개념들이니 꼭 숙지하기 바란다.
'Programming > Python' 카테고리의 다른 글
25. 상속(Inheritance) (0) | 2021.03.28 |
---|---|
23. 가비지 컬렉터(Garbage Collector) (0) | 2021.03.28 |
22. 클래스의 추가적인 구문 (0) | 2021.03.27 |
21. 클래스 (0) | 2021.03.26 |
20. 모듈 만들기 (0) | 2021.03.25 |
댓글