Object-Oriented Programming - Property Decorators
Contents
- Refactoring Hell
- Property Decorators
Refactoring Hell
class Student:
def __init__(self, first, last, health):
self.first = first
self.last = last
self.health = health
self.email = first + '.' + last + '@korea.ac.kr'
def fullname(self):
return f'{self.first} {self.last}'
stu_1 = Student('Tom', 'Lee', 100)
>>> print(stu_1.first) #attribute
Tom
>>> print(stu_1.fullname()) #method
Tom Lee
>>> print(stu_1.email) #attribute
Tom.Lee@korea.ac.kr
>>> stu_1.first = 'Thomas' #update first attribute
>>> print(stu_1.first) #attribute
Thomas
>>> print(stu_1.fullname()) #method
Thomas Lee
>>> print(stu_1.email) #attribute
Tom.Lee@korea.ac.kr
위 예시에는 한가지 문제점이 있다.
-
stu_1
인스턴스를 생성 -
fullname()
메서드를 호출 -
email
attribute 호출
위 3가지 코드는 정상적으로 실행된다. 하지만 stu_1.first
를 Tom
에서 Thomas
라는 값으로 업데이트를 한 뒤 똑같이 출력을 해보면,
-
stu_1.first
는Thomas
로 정상적으로 update -
stu_1.fullname()
메서드도 update 된stu_1.first
를 통해 호출 -
stu_1.email
은 업데이트 되기 전Tom.Lee@korea.ac.kr
로 고정
first
는 업데이트 되었지만 email
은 업데이트 되지 않았다. 왜일까?
email
은 first
를 통해 정의되는 attribute 이지만, email
attribute 는 인스턴스가 생성되는 그 순간 이미 정의되기 때문이다. 즉, stu_1.email
을 직접적으로 update 하지 않는 이상 first
를 update 하더라도 email
은 고정이다.
fullname()
메서드는 업데이트된 값으로 정상적으로 호출된다. 메서드는 본질적으로 함수이기 때문에 call 되는 순간 scope 에 올려지기 때문이다. 그렇다면 email
도 업데이트 된 first
를 반영하기 위해 메서드로 만들면 된다.
def email(self):
return f'{self.first}.{self.last}@korea.ac.kr'
하지만 기존에 attribute 였던 코드를 메서드로 고치는 순간 아주 큰 문제가 발생한다. 기존의 사용자들은 인스턴스의 이메일을 호출하기 위해 자신의 코드를 전부 stu_1.email
에서 stu_1.email()
로 고쳐야 된다는 refactoring 문제에 직면한다.
넘파이 모듈을 예시로 들어보자.
np.ndim
을 통해 객체의 차원을 호출하던 사용자들은 전부np.ndim()
으로 고쳐야 할 것이다. 넘파이 개발자들이 이 수정을 하는 순간 전세계에 넘파이를 사용하는 모든 웹앱과 딥러닝 프레임워크는 이 작은 변화를 위해 수천 줄의 코드를 수정해야 하는 대참사가 벌어진다.
Property Decorators
바로 이런 상황을 위해 property decorator 가 존재한다.
class Student:
def __init__(self, first, last, health):
self.first = first
self.last = last
self.health = health
def fullname(self):
return f'{self.first} {self.last}'
@property
def email(self):
return f'{self.first}.{self.last}@korea.ac.kr'
>>> stu_1 = Student('Tom', 'Lee', 100)
>>> stu_1.first = 'Thomas'
>>> print(stu_1.first)
Thomas
>>> print(stu_1.fullname())
Thomas Lee
>>> print(stu_1.email)
Thomas.Lee@korea.ac.kr
Property decorator 을 통해 기존에 attribute 였던 email
을 property 메서드로 새로 정의했다. Property 메서드는 메서드를 호출 할 시 ()
를 포함하지 않아도 된다는 특징이 있다. 그렇기에 기존 코드를 사용하던 유저들은 stu_1.email
코드를 그대로 사용할 수 있게 된다.
Property decorator 는 인스턴스가 이미 선언된 후 인스턴스의 attribute 를 재정의 할 때 유용하다.