티스토리 뷰

7.4 불변 객체와 가변 객체(Immutable Objects vs. Mutable Objects)

 

- 가변 객체(mutable object)를 함수에 전달할 때, 가변 객체의 내용물 바꿀 수 있다.

- 숫자(numbers)문자열(strings)불변 객체(immutable objects)이다.

- 이러한 불변 객체의 내용물바뀌지 않는다.

- 하지만, 가변 객체(mutable object)를 함수에 전달한다면 이 객체의 내용물을 바꿀 수 있다.

- 아래의 예제가 불변 객체(Immutable Objects)가변 객체(mutable Objects)차이점을 보여주는 예제이다.

 

* 불변 객체와 가변객체 예제(TestPassMutableObject.py)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
from Circle import Circle
 
def main():
    # 반지름이 1인 circle 객체 생성
    myCircle = Circle()
 
    # 반지름이 1,2,3,4,5 인 원의 넓이를 출력
    n = 5
    printAreas(myCircle, n)
 
    # myCircle.radius 와 times 출력
    print("\nRadius is", myCircle.radius)
    print("n is ",n)
 
def printAreas(c, times):
    print("Radius \t\tArea")
    while times >= 1:
        print(c.radius, "\t\t", c.getArea())
        c.radius = c.radius + 1
        times = times - 1
 
main()
 
cs

 

 

- 앞서 정의한 Circle 클래스를 이용. 이 프로그램은 printArea(myCircle, n)을 호출하기 위해 Circle 객체인 myCircleint 객체인 n전달한다.

- 함수에 객체를 전달할 때, 객체의 레퍼런스(reference)전달한다.

- 불변 객체(immutable object)를 전달하는 것과 가변 객체(mutable object)를 전달하는 것에는 중대한 차이점이 몇 가지 있다.

숫자(number)문자열(string)과 같은 불가변 객체의 인자(arguments)에 대해서, 함수 안에서 내용물들이 바뀌면 함수 밖에서는 객체에 처음 할당한 값(전달하기 전의 값)이 변하지 않는다.

 

■ circle과 같은 가변 객체의 인자에 대해서는, 함수 안에서 객체의 내용물들이 바뀌면 밖에서도 객체에 처음 할당한 값(전달하기 전의 값)이 바뀐다.

 

- 위 예제를 바탕으로 예를 들어보자면, line 20의 가변 객체인 Circle c의 radius는 1씩 증가한다.

- c.radius + 1 는 새 int 객체를 만들고, 이를 c.radius에 할당시킨다.

- myCirclec모두 동일한 객체(전달된 객체의 레퍼런스가 전달되었기 때문에)를 가르킨다.

- printArea 함수가 끝이 났을 때, line 12에서 c.raidus는 6이고 myCircle.radius 역시 6으로 출력된다.

- line 20에서 times - 1 은 새 int 객체를 만들고, 이를 times에 할당시킨다.

- 하지만 n은 불가변 객체이기 때문에 printAreas 함수 밖에서는 여전히 n = 5 이다.

- 그래서 line 13에서 여전히 5가 출력된다.

 



 

7.5 데이터 필드 숨기기(Hiding Data Fields)

- 데이터 필드(data field)비공개(private)로 만들면 데이터를 보호 할 수 있고 클래스를 좀 더 쉽게 유지할 수 있다.

- 우리는 객체의 인스턴스 변수(instance variable)를 통해 아래와 같이 데이터 필드(data field)에 접근이 직접 가능하다.

>>> c = Circle(5)

>>> c.radius = 5.4 # 인스턴스 변수에 직접 접근

>>> print(c.radius) # 인스턴스 변수에 직접 접근

5.4

>>>

 

- 하지만, 이렇게 객체의 데이터 필드에 직접 접근하는 것은 아래와 같은 이유로 바람직하지 못하다.

 

■ 데이터가 쉽게 손상될 수 있다. 예를 들어, TV 클래스의 channel(1부터 120까지의 수)에 실수로 범위 밖의 숫자를 할당할 가능성이 높아진다.

ex) tv1.channel = 125

 

■ 클래스의 유지와 버그에 취약해진다. 이미 Circle 클래스를 사용한 상태에서 이 클래스의 radius 값을 양수만 할당하게 수정하고 싶다고 가정해보자. 클라이언트가 radius값을 myCircle.radius = -5 라는 형식으로 직접 접근하여 수정하였다면, Circle 클래스만 수정해야하는 것이 아니라 전체 프로그램 자체를 수정해야하는 일이 발생 할 수 있다.

 

- 이러한 문제들을 방지하기 위해선, 클라이언트데이터 필드에 직접 접근 할 수 없게 해야한다. 이를 데이터 숨기기(data hiding)라고 부른다.

- 이는 프라이빗 데이터 필드(private data field)를 정의함으로써 데이터를 숨긴다.

- 프라이빗 데이터 필드는 선행 밑줄 2개로 정의한다.

- 프라이빗 메소드(private method) 역시 선행 밑줄 2개로 정의한다.

 

- 프라이빗 데이터필드메소드클래스 에서만 접근이 가능하며 클래스 에서는 접근이 불가능하다.

- 클라이언트(client)프라이빗 데이터 필드에 직접 접근이 가능하게 만들어주는 메소get 메소드도 제공한다.

- 클라이언트프라이빗 데이터 필드를 수정할 수 있게 만들어주는 메소드set 메소드도 제공한다.

- 통상적으로 get 메소드를 getter(or accessor)라고 부르고, set 메소드를 setter(or mutator)라고 부른다.

 

* get 메소드 형식

def getPropertyName(self):

- 만약 반환 타입boolean 이라면, get 메소드는 아래와 같은 형식으로 사용한다.

 

* get 메소드 반환타입이 boolean인 경우 형식

def isPropertyName(self):

*set 메소드 형식

def setPropertyName(self):

 

- 이전에 사용했던 Circle 클래스를 수정하여 radiusprivate로 정의해 보자.

- radius 앞에 밑줄 2개를 작성하면 된다.(__radius)

 

* radius를 private로 정의하기

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import math
 
class Circle:
    #circle 객체 생성
    def __init__(self, radius = 1):
        self.__radius = radius
 
    def getPerimeter(self):
        return * self.__radius * math.pi
 
    def getArea(self):
        return self.__radius * self.__radius * math.pi
 
    def setRadius(self, radius):
        self.__radius = radius
cs

 

 

 

- Circle 객체의 radius는 직접 접근이 불가능하다.

- 하지만 getRadius() 메소드를 이용해 값을 읽을 수는 있다. getRadius는 radius를 반환한다.

- c.__radius로 radius에 직접 접근 할 시 오류가 난다. 이는 radius가 private로 정의되었기 때문이다.

 

참고 문헌 : Introduction to Programming Using Python / Y.DANIEL LIANG



본 게시물은 개인적인 용도로 작성된 게시물입니다. 이후 포트폴리오로 사용될 정리 자료이니 불펌과 무단도용은 하지 말아주시고 개인 공부 목적으로만 이용해주시기 바랍니다.


교재 영어 원서를 직접 번역하여 정리한 게시물이므로 일부 오타, 의역이 존재할 수 있습니다. 틀린 부분이 있다면 댓글로 알려주시면 감사하겠습니다. 

댓글