inflearn logo
강의

강의

N
챌린지

챌린지

멘토링

멘토링

N
클립

클립

로드맵

로드맵

지식공유

타입 파이썬! 올바른 class 사용법과 객체지향 프로그래밍

캡슐화 (encapsulation) - @property | getter와 setter

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

308

김백현

작성한 질문수 4

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라고만 나오는데, 실제 내부 코드를 보려면 어디로 가야 할까요?

oop python

답변 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 깃 허브에서 확인하실 수 있습니다.

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

감사합니다.

0

김백현

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

0

김백현

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

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

(예시 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가 빈 괄호의 사용에 있어서 뭔가 다르게 돌아가는데
이 차이는 대체 무엇인지 궁금합니다 ㅠㅠ

0

윤상석

네 맞습니다.

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

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

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

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

도움이 되었을까요?

0

김백현

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

보너스 챕터 마지막 강의 녹화 품질이 문제가 있습니다ㅠㅠ

0

119

1

린터 설치문의

0

371

2

데이터분석에서의 가상환경

0

401

0

print(Robot.how_many()) 하면 None이 뜨는 이유

2

328

2

타입파이썬 문의

1

342

1

프레임워크 질문

1

239

1

문수미님과 같은 내용입니다

1

316

1

클래스 상속 순서? 질문

1

387

2

pip과pip3의 차이

1

2749

1

메서드 리턴 값이 print일 때 print를 찍으면 None

1

250

1

변수의 참조에 대해서 질문입니다.

1

248

1

질문입니다..

1

209

1

pyright 를 이용한 클래스 재정의 코드 실행 문제점 질문 드립니다.

1

456

1

which pyhon이 왜 안될까요..?

1

440

1

pyright 에러나서 질문드립니다.

1

399

1

클래스 변수 관련 질문입니다.

1

303

1

데코레이터 관련 질문

1

230

1

venv 로 만든 가상환경은 파이썬 버젼을 변경하기가 어려운 것 같습니다.

1

1121

1

Final로 타이핑한 변수에 list를 넣는다면

1

228

1

생성자에서 자기 자신 타이핑 하는 경우

1

220

1

f"{객체}" 출력값에서의 숫자값과 id(객체)에서의 숫자값의 차이가 무엇인가요??

1

337

1

타입힌트 실무에서 자주쓰이나요?

2

487

1

스태틱메소드와 클래스메소드

3

267

1

인스턴스와 데이터

2

238

1