지난번 포스팅에서 파이썬의 클래스에 대해 설명했었다.
이번에는 속성과 메서드의 종류에 대해 설명해보고자 한다.
앞에서 배웠던 내용을 정리해보면,
인스턴스나 클래스에서 속성을 사용할 때는 인스턴스 -> 클래스 -> 부모클래스 -> 조상클래스까지 순서대로 조회하면서, 찾는 이름의 속성이 나오는 순간 다음으로 넘어가지 않고 사용한다.
그런데 만약 동일한 이름의 속성을 사용하고 싶다면 어떻게 해야할까?
예를 들어, class 학교
상속하는 class 학생
이 있다면, 학교에도 name
이 있고 학생도 name
이 있을 것이다. 이 때, 학생의 instance에서 이름을 사용하려면 intstance.name="KIM"
을 선언하면 되지만, 그러면 해당 instance는 학교의 name을 사용하지 못하게 된다. (덮어쓰기가 되므로)
class School :
name = "청담중학교"
class Student(School):
name = "학생이름"
이렇게 속성이 중복되는 경우에 학교의 이름과 학생의 이름을 구분짓고 싶을 것이다.
이럴 때 첫번째 해결방법은, 각 클래스마다 속성이름을 다르게 짓는 것이다.
class School :
name_school = ""
class Studnet(School) :
name_student = ""
두번째 해결 방법은, 맹글링(mangling)을 사용하는 방법이다.
대부분의 파이썬 코드에서 따르는 규약이 있다.
밑줄로 시작하는 이름 (예를 들어, _name)은 API의 비공용 부분으로 취급되어야 한다.
그 이름의 데이터타입이 무엇이던 상관없이 그러하다. (함수/메서드, 속성/변수)
밑줄로 시작하는 이름은 구현 세부/상세사항으로 취급되고, 예고없이 변경될 수 있다.
이 비공개 변수를 사용하면, 서브클래스와 비공개 변수의 충돌을 피할 수 있다.
이렇게 쉽고 유효한 수단이 있기 때문에, 파이썬에서는 이름이 뒤섞이는 것에 대한 기술적인 지원을 별로 하지 않는다.
(*네임 맹글링 : name mangling - 변수이름에 _
를 섞어서 짓이겨 버리기.)
(* 다른 언어와 달리, 파이썬에는, 객체 내에서만 액세스(접근)가능한, 비공개 인스턴스 변수가 존재하지 않는다.)
맹글링의 사용 사례를 몇개 찾아보자.
class School :
def __init__(self) :
self.name = "청담중학교"
self.loc = "서울"
self.born = "1990년 1월 15일"
school = School()
print(school.name, school.loc, school.born)
# 청담중학교 서울 1990년 1월 15일
class School :
def __init__(self) :
self.name = "청담중학교"
self.loc = "서울"
self.__born = "1990년 1월 15일"
school = School()
print(school.name, school.loc, school.__born)
# AttributeError: 'School' object has no attribute '__born'
여기에서 특이한 점은, 속성 born 앞에 __를 붙였을 뿐인데 같은이름으로 호출하면 에러가 발생한다는 것이다.
이를 보면, 맹글링을 적용하면
1. 하위클래스가 상위클래스의 속성을 덮어쓰거나
2. 하위클래스에서 동일한 이름을 사용할 수 있다.
맹글링을 통해서 '비공개처리'를 한다고 했는데, 그러면 이 데이터에 접근할 수 있는 방법은 없을까? 인스턴스와 클래스에 dir()을 사용해서 어떤 차이가 있는지 살펴보자.
class School :
def __init__(self) :
self.name = "청담중학교"
self.loc = "서울"
self.__born = "1990년 1월 15일"
school = School()
print(dir(School))
['__class__', '__delattr__', '__dict__', '__dir__','__doc__' ...]
print(dir(school))
['_School__born', '__class__', '__delattr__', '__dict__', '__dir__', '__doc__', ...
'loc', 'name']
코드를 보면, 인스턴스에는 'name', 'loc'뿐만이 아니라 '_School__born' 이라는 속성이 생긴것을 알 수 있다. 즉, 파이썬의 비공개변수
는 접근을 조금 더 까다롭게 만들 뿐이지, 아예 접근하지 못하도록 하는 방법은 없다.
정리하자면 Python 에서는 Information Hiding (정보은닉) 기능은 존재하지 않는다.하지만, __
(double underscore)를 통해 “접근금지” 라는 의사표현을 Name Mangling 을 통해 가능하다.
그렇다면 _
를 하나만 넣으면 어떨까?
변수 앞에
_
를 하게되면, 접근을 자제하라는 경고, (자바의 protected 제한자와 유사)
__
는 강한 접근 거부 의사를 표현하는 것이라고 볼 수 있다. (자바의 private 제한자와 유사)
😳 그렇다면 __init__ , __str__ 등은 보호되는건 아닌데 뭘까? 정답을 찾지 못했다...
위의 비공개 변수 처리는 속성 뿐만이 아니라 메서드에서도 동일하게 적용된다.
여기까지 우리는 파이썬에서, 클래스가 상속해줄 때, 숨기고 싶은 데이터의 처리는 \_
또는\_\_
를 사용하면 된다는 것을 알게되었다.
class Test :
def __hello(self) :
print("hello")
test2 = Test()
test2.__hello()
#AttributeError: 'Test' object has no attribute '__hello'
print(dir(test2))
['_Test__hello', '__class__', '__delattr__', '__dict__',...]