[코드잇] 쉽게 배우는 파이썬 문법 - 프로퍼티(Property) 3편

코드잇

안녕하세요, 온라인 코딩 스쿨 코드잇입니다.

​

오늘은 지난 시간에 이어 파이썬의 프로퍼티에 대해서 알려드리도록 하겠습니다.

​

쉽게 배우는 파이썬 문법 - 프로퍼티(Property) 1편

쉽게 배우는 파이썬 문법 - 프로퍼티(Property) 2편

​

이번에는 프로퍼티가 어떤 원리로 동작하는지를 설명해드리려고 합니다. 하지만 그 전에 알아야할 게 있습니다.

​

그건 바로 파이썬의 디스크립터(Descriptor)가 무엇인지를 아는 겁니다.

​

파이썬에서 하나의 객체(A)는 다른 객체(B)를 속성으로 가질 수 있습니다. 이때 속성이 되는 그 객체(B)의 값을

​

- 읽거나,

- 쓰거나,

- 그 객체를 속성에서 삭제하려고 할 때

​

이루어질 동작이 미리 정의된 객체(B)를 디스크립터라고 합니다.

​

이건 말로만 설명하면 이해하기 어려우니 코드를 보여드릴게요. 아래와 같은 코드가 있다고 해봅시다.

​

class CharacterInfo:
    def __init__(self, power, speed):
        self.power = power
        self.speed = speed

    def __get__(self, obj, objtype):
        print('(GET)정보 조회됨')
        return ('공격력 : '+str(self.power) + ' / 스피드 : ' + self.speed)

    def __set__(self, obj, val):
        print('(UPDATE)정보 갱신 시작')
        self.power = val.power
        self.speed = val.speed

    def __delete__(self, obj):
        print('(DELETE)정보 삭제하기')
        self.power =''
        self.speed = ''


class Guardian:
    info = CharacterInfo(10, '50km/h')


g1 = Guardian()   # g1 이라는 수호천사 인스턴스 하나 생성
print(g1.info)   # 인스턴스 g1의 초기 정보 출력 
info_after_upgrade = CharacterInfo(15, '70km/h')   # 업그레이드 아이템 적용 후 캐릭터 정보
g1.info = info_after_upgrade   # 새 캐릭터 정보를 인스턴스 g1 에 설정
print(g1.info)   # 인스턴스 g1의 정보 출력
del g1.info   # 인스턴스 g1의 정보 삭제
print(g1.info)   # 인스턴스 g1의 정보 출력

지금 어떤 게임의 캐릭터 중에서 수호천사 캐릭터를 나타내는 Guardian 클래스와 각 캐릭터의 정보(공격력과 스피드)를 담고있는 Characterinfo 클래스가 있습니다. 수호천사 캐릭터라면 모두 같은 공격력과 스피드를 가질테니까 Guardian 클래스 안에 Characterinfo 클래스의 인스턴스를 info 라는 클래스 변수(속성)로 두었습니다.

​

Info 클래스를 살펴보면 캐릭터의 공격력을 나타내는 power, 스피드를 나타내는 speed 라는 인스턴스 변수를 갖고 있습니다. 그리고 우리가 자주 봐온 인스턴스 초기화를 위한 __init__ 메소드도 있네요. 그런데 익숙하지 않은 메소드들이 보이네요? 지금

​

__get__ 메소드와

__set__ 메소드와

__delete__ 메소드가

​

정의되어 있는데요.

바로 이런 메소드들이 정의되어 있는 클래스로 만든 객체를 디스크립터라고 합니다.(꼭 3가지 메소드 다 정의되어 있을 필요는 없습니다. 3가지 중 하나만 있어도 디스크립터입니다.) 이런 메소드들은 어떤 역할을 하는 걸까요?

​

지금 CharacterInfo 클래스와 Guardian 클래스를 사용하는 실행 코드에는 각 줄마다 주석이 달려있는데요. 수호천사 인스턴스의 초기 정보를 출력하고, 아이템으로 업그레이드 후에 정보를 재설정하고, 정보를 아예 삭제하는 코드입니다. 코드를 실행하면, 이런 결과가 출력됩니다.

(GET)정보 조회됨
공격력 : 10 / 스피드 : 50km/h
(UPDATE)정보 갱신 시작
(GET)정보 조회됨
공격력 : 15 / 스피드 : 70km/h
(DELETE)정보 삭제하기
(GET)정보 조회됨
공격력 :  / 스피드 :

캐릭터 정보(공격력과 스피드)가 출력되는 부분은 출력된 이유를 알겠는데 (GET)정보 조회됨 , (UPDATE)정보 갱신 시작 , (DELETE)정보 삭제하기 같은 문자열은 왜 출력됐을까요? 바로 그 이유에 디스크립터의 비밀이 숨어있습니다.

​

위 코드 내용 중

1. print(g1.info) 에서 이 부분(g1.info)이 실행될 때 CharacterInfo 클래스의 __get__ 메소드가 실행되기 때문에 그렇습니다.((GET)정보 조회됨 출력)

2. 이 부분(g1.info = new_info )이 실행될 때는 CharacterInfo 클래스의 __set__ 메소드가 실행되기 때문에 그렇습니다.((UPDATE)정보 갱신 시작 출력)

3. 이 부분(del g1.info)은 g1 인스턴스에서 info 속성을 없애라는 명령입니다. del은 어떤 인스턴스의 속성을 삭제할 때 사용되는 함수입니다. del g1.info 가 실행될 때는 CharacterInfo 클래스의 __delete__ 메소드가 실행되기 때문에 그렇습니다.((DELETE)정보 삭제하기 출력)

​

그러니까 파이썬에서는 클래스 안에

__get__ 메소드를 정의하면 그 클래스의 인스턴스를 읽으려고 할 때 __get__ 메소드가 실행되고,

그 클래스의 인스턴스를 설정하려고 할 때는 __set__ 메소드가 실행됩니다.

그리고 그 인스턴스를 속성 중에서 없애려고 할 때는 __delete__가 호출되구요.

​

그럼 각 메소드의 파라미터의 의미는 뭘까요?

먼저 def __get__(self, obj, objtype): 에서

self 는 디스크립터 자신(디스크립터도 하나의 인스턴스니까요)

obj 는 디스크립터를 자신의 속성으로 갖고 있는 바로 그 인스턴스

objtype 은 obj 의 클래스를 말합니다. 지금 이 경우에는 Guardian 클래스겠죠?

​

그리고 def __set__(self, obj, val): 에서

self, obj 는 __get__ 메소드의 것과 같은 파라미터입니다.

val 는 새로 설정되는 인스턴스를 말합니다. 그러니까 g1.info = new_info 이 코드에서 new_info를 말하는 것이죠. 그러니까 지금 아까 __set__ 메소드에서 아래처럼 val 파라미터의 power 속성과 speed 속성을 가져온 것이죠.

def __set__(self, obj, val):
        print('(UPDATE)정보 갱신 시작')
        self.power = val.power
        self.speed = val.speed

마지막으로 def __delete__(self, obj): 에서

self, obj 는 __get__ 메소드의 것과 같은 파라미터입니다.

​

각 메소드의 파라미터의 의미가 이해가 되시죠?

이제 디스크립터가 뭔지 정리해드릴게요.

​

__get__ 메소드, __set__ 메소드, __delete__ 메소드 중 하나라도 정의된 클래스가 있을 때, 그 클래스로 만든 인스턴스를 바로 디스크립터(descriptor)라고 하는 겁니다. 그리고 이 디스크립터를 다른 클래스에서 그 속성으로 사용했을 때 상황에 맞는(값 읽기, 값 설정, 값 삭제) 디스크립터의 각 메소드가 호출되는 겁니다.

​

디스크립터가 뭔지 이해되셨나요? 이런 기능이 왜 필요한지 궁금할 수도 있는데요. 이 디스크립터는 파이썬에서 프로퍼티(property), 클래스 메소드(classmethod), 정적 메소드(staticmethod) 등을 만드는 기본 토대가 되는 중요한 개념이자 규약입니다. 다음 번에 디스크립터에 대해 조금 더 깊은 내용을 알아봅시다.

​

​

기업문화 엿볼 때, 더팀스

로그인

/