이하의 글은 2010년에 쓴 것입니다. 오래된 글인 만큼, 현재의 생각과 전혀 다른 내용도 많이 포함되어 있고, 당시와는 상황이 많이 달라진 점도 있습니다. 또한, 그 당시에 잘못 알려졌던 정보도 포함되어 있을 수 있습니다. 어찌됐든 저는 제 오래된 글이 회자되는 것을 저어합니다. 읽기에 앞서 양해를 부탁드립니다.
Python에서 getter/setter는 죄악
링크한 Reddit (/r/Python) 글타래 Diving in to Python from Java. What should I know?를 보면 이런 종류의 글타래에는 보통 별로 볼 것 없는 댓글이 많은데 반해, 이 글에는 생각보다 괜찮은 조언이 많이 보인다. /* … */
꼴의 여러줄 주석이 없는 이유1, //
대신 #
을 주석으로 쓰는 이유2, Javadoc 쓰지 말고 Sphinx 쓰라는 얘기, 상속으로만 다형성을 만들게 아니라 덕 타이핑을 잘 활용하라는 얘기 등등. (사실 나도 모든 조언에 전적으로 동의하는 것은 아니다.)
그건 그렇고 내가 하고자 하는 얘기는 사실 아래 인용한 댓글에 대해서다.
One thing to be very careful of is that you can write Java in any language. Do not do so! A big initial clue is you start writing getters and setters. (I was guilty of that in my first Python program.)
Java를 쓰던 많은 사람이 다른 언어를 배울 때도 무턱대고 getter/setter를 쓰려고 하는데, 이건 프로퍼티(property) 기능이 없어서 생겨난 Java 언어만을 위한 관용구기 때문에 Python에서 쓸 하등의 이유가 없다.
그럼 어떻게 해야 하나? Python에서는 다음과 같은 옵션이 존재한다.
그냥 애트리뷰트(attribute) 그대로 노출한다. Java에서는 하지 않는 짓이다. 왜냐하면 나중에 애트리뷰트에 접근하는 지점에 어떤 부가적인 오퍼레이션을 넣고자 하면 뒤늦게 getter/setter가 필요해질텐데, 그렇게 되면 인터페이스가 달라져서 해당 객체에 의존하는 다른 기존 코드가 깨지기 때문이다. 이 문제는 아래(2)에서 설명하는 프로퍼티(property) 기능 덕분에 걱정할 필요가 없다.
또 다른 문제는 Java에 프로퍼티 기능이 있다고 하더라도 코드 수준의 인터페이스는 호환되는데 반해 바이너리 수준의 인터페이스가 호환되지 않아 전체 소스 코드를 다시 컴파일해야 하기 때문이다. (C#을 보라.)
애트리뷰트 그대로 노출하다가, 부가적인 로직이 필요해졌을 때만
property
를 사용한다.property
는 기본적으로는 다음과 같이 사용한다.age = property(lambda self: (self.birthday - datetime.date.today()).days / 365)
데코레이터(decorator) 문법을 이해하고 있다면 저걸 다음과 같이 쓸 수도 있다는 것을 알아챌 것이다.
@property def age(self): interval = self.birthday - datetime.date.today() return interval.days / 365
사용하는 문법은
object.age
와 같이 애트리뷰트 접근과 완전히 똑같기 때문에 처음 디자인 할 때는 애트리뷰트를 그대로 노출하다가 나중에 프로퍼티로 갈아치워도 인터페이스가 달라지지 않는다. 완전히 똑같다는 얘기는 바이트코드 수준에서도 접근 방식이 동일한 바이너리로 다뤄진다는 얘기이다. 즉, C#과 같이 빌드를 다시 해야하는 수고도 없다.
여러줄 주석은 임시로 코드 일부분을 막거나, 코드를 문서화 하는데 사용된다. 어느 쪽이든 3중 인용부호로 된 여러줄 문자열 리터럴을 사용하면 된다. 전자는 최종 코드에는 없을 것이기 때문에 그렇게 해도 되고, 후자는 원래 그런 용도로 docstring을 쓰기 때문에 그렇다.↩
당연히 Unix의 셔뱅(shebang) 때문.↩