• 카테고리

    질문 & 답변
  • 세부 분야

    프로그래밍 언어

  • 해결 여부

    미해결

setter 설정 후, 인스턴스 변수에 새로운 값을 set할 때

21.07.27 14:28 작성 조회수 110

1

왜 클래스의 메소드 문법을 따르지 않고, 변수를 선언하는 문법을 따르는 것인가요?

가령, robot1 = Robot('siri', 14) 의 인스턴스에 대해서 14를 24로 바꾸고 싶으면

robot1.age(24)로 해야 할 것 같은데, 왜 이것은 int object is not callable이라는 오류가 발생하고
robot1.age = 24와 같이 해야만 정상적으로 새로운 값이 set이 되는데요

이것은 @property라는 데코레이터에 매치되는 함수와, @age.setter라는 데코레이터에 매치되는 함수가 정의된 방식이 서로 다르기 때문인가요?

+ 추가 질문
제가 보기에는 getter와 setter의 사용법이 일관되지가 못한데, 이런 것들이 버전업을 고치며 일관성있게 통일이 되기도 하는가요?

+ 추가 질문
파이참에서 두 데코레이터(property, age.setter)의 내부 코드를 보려고 하니 죄다 pass라고만 나오는데, 실제 내부 코드를 보려면 어디로 가야 할까요?

답변 1

답변을 작성해보세요.

3

안녕하세요. 김백현님 :)

먼저 관련 예제 코드를 가지고 답변을 드리겠습니다.

위 코드에서 siri.age를 하는 순간 @property def age(self) 함수가 자동으로 호출되고 siri.age = 25를 하는 순간 @age.setter def age(self, new_age) 함수가 자동으로 호출되며 siri.age = 25의 25가 new_age로 들어간 것을 확인할 수 있습니다.

이때 siri.age = 25 가 아니라 siri.age(25)가 더 자연스러운데 왜 이렇게 작동하도록 설계되는지에 대한 답변을 드리겠습니다.

이해하기 쉽도록 먼저 C++에서 getter와 setter를 사용하는 코드를 보여 드리겠습니다.

(위 코드에서 print는 파이썬과 유사하게 보여드리기 위해 따로 구현했습니다.)
(위 코드를 이해안하셔도 됩니다.)

C++에서는 int main( ) { ... } 부분을 보시면 김백현님이 말씀하신 것처럼 siri.setAge(24)를 사용하여 값을 변경합니다.

(이와 달리 해당 코드를 파이썬 방식으로 짠다면 siri.age = 24로 변경하게 되는 것이죠.)

파이썬 같은 경우에도 @property와 @age.setter를 사용하지 않고 C++과 동일한 방식으로 getter와 setter를 구현할 수 있습니다.

위 코드는 siri.age = 24 대신에 siri.setAge(24)로 세터를 사용하도록 되어 있습니다.

하지만 파이썬을 만든 개발 팀에서는 개발자들을 위해 가독성을 높이고 일관성을 유지하도록 코드를 짤 수 있도록 @property와 @변수.setter를 제공해주는 것이지요.

따라서 파이썬스러운 코드로 게터와 세터를 구현한다면 @property와 @변수.setter를 사용하는 것입니다.

파이썬 뿐만 아니라 현대 언어중 Typescript 또한 비슷한 방식으로 인터페이스를 제공해줍니다.

+ 추가 질문
제가 보기에는 getter와 setter의 사용법이 일관되지가 못한데, 이런 것들이 버전업을 고치며 일관성있게 통일이 되기도 하는가요?

-> 말씀드린 것처럼 getAge, setAge처럼 따로 게터와 세터를 정의할 수 있지만 @property와 @변수.setter는 개발자의 편의를 위해서 제공해주는 파이썬의 내장 데코레이터입니다. 함수인데 함수답지 않아서 일관성이 없을 수 보이지만 파이썬 개발팀의 의도에 맞게 사용하면 좋을 것 같습니다. :)

(파이썬 개발팀에서 만들어준 데코레이터를 사용해서 일반적인 함수에서 특수한 함수로 변한 것이죠.)

+ 추가 질문
파이참에서 두 데코레이터(property, age.setter)의 내부 코드를 보려고 하니 죄다 pass라고만 나오는데, 실제 내부 코드를 보려면 어디로 가야 할까요?

-> 파이썬 언어 자체에 대한 내부 코드는 https://github.com/python/cpython/tree/main/Python 깃 허브에서 확인하실 수 있습니다.

파이썬 언어는 자체적으로 제공해주는 것이 많고 내부적으로 자신도 모르게 돌아가는 것이 많다보니 어려울 수 있습니다. 관련해서 추가적으로 궁금하신 것이 있다면 편하게 말해주세요. :)

감사합니다.

김백현님의 프로필

김백현

질문자

2021.07.28

와... 어떻게 이렇게까지 상세한 답변을 해 주실 수 있으신건가요? ㅠㅠ 감사합니다 많은 도움 되었습니다!

김백현님의 프로필

김백현

질문자

2021.07.28

앗 그리고 하나 더 여쭤보고 싶은 게 있는데요.

인자를 받지 않는 인스턴스 메소드에 대해서, 메소드 뒤에 빈 괄호를 넣지 않고도, 해당 메소드를 실행 가능하게 하는 것 또한 '파이써닉한' 혹은 '쓰기 좋게 만든 것'으로 이해하면 되나요?

(예시 1)
이 질문과 관련해서, get을 할 때는 print(siri.age)가 아니라 print(siri.age())를 쓰고 있는 반면

(예시 2)
import numpy as np
array1 = np.array([1, 2, 3])
에서 array1의 dimension을 확인할 때
print(array1.dim())이 아니라 print(array1.dim)을 사용해야 해서

예시 1과 예시 2가 빈 괄호의 사용에 있어서 뭔가 다르게 돌아가는데
이 차이는 대체 무엇인지 궁금합니다 ㅠㅠ

네 맞습니다.

(예시 2)의 내부 코드는 아래의 방식으로 numpy 클래스 안에서 동작하는 것이죠. (실제 구현은 다를 수 있습니다.)

@property
def dim(self):
    # dimension을 구하는 코드
    return result

이렇게 클래스 내부에서 정의되고 사용자(개발자)가 사용할때는 array1.dim 이런식으로 사용하는 겁니다.

즉, property 데코레이터를 사용하면 기능을 수행하는 변수처럼 사용할 수 있는 것이죠.

도움이 되었을까요?

김백현님의 프로필

김백현

질문자

2021.07.28

네 큰 도움 되었습니다. 덕분에 getter와 setter가 어떤 식으로 녹아들어가 있는지 감을 잡게 되었네요!