goodthings4me.tistory.com
■ 파이썬의 객체 외부에서 객체 내에 있는 변수(속성)나 메서드를 수정할 수 없게 하기 위한 코딩 규칙은 attribute, method 앞에 밑줄('_', undercore) 하나를 붙이는 것이다.
그리고, __dict__ 메서드로 변수(속성)정보를 확인하고, 속성값을 수정할 수 있지만, 이를 제한하고 싶을 경우 밑줄 두 개를 붙이는 방법이 있다.
# 변수(속성)값을 수정할 수 있다. (잘못된 접근과 값의 수정)
class Person:
def __init__(self, n, a):
self.name = n
self.age = a
def __str__(self):
return '{0}: {1}'.format(self.name, self.age)
def main():
p = Person('James', 22)
print(p)
print(dir(p))
p.age -= 1
print(p)
print(p.__dict__) # {'name': 'James', 'age': 21}
main()
※ __dict__ 는 해당 객체 내에 있는 변수(속성) 정보를 담고 있는 딕셔너리로 파이썬 각 객체마다 가지고 있는 속성임
▷print(dir(p)) 결과
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'age', 'name']
# __dict__ 를 통해 변수의 값을 수정할 수 있다.
class Simple:
def __init__(self, name):
self.name = name
def __str__(self):
return '이름은 %s 입니다.' % self.name
def main():
sp = Simple('Kim')
print(sp)
sp.__dict__['name'] = 'Park'
print(sp)
main()
[실행 결과]
이름은 Kim 입니다.
이름은 Park 입니다.
■ 파이썬의 정보은닉(Infomation Hiding)
파이썬에는 접근지정자라는 개념이 없지만, 객체(인스턴스) 변수(또는 메소드) 앞에 밑줄('_', underscore) 한 개를 붙여 private 표현을 한다. 즉, 개발자들 간의 약속, "밑줄(_) 한 개가 붙으면 private 속성이니 접근하지 말라는 명시적 표현"이라는 의미이다.
# 참고로, 밑줄 두 개를 붙이면 외부 접근이 불가한 private 효과를 만들 수는 있지만, 실제로 private은 아니다.
# 이는 Name Mangling(내부적인 어떤 규칙을 통해 함수의 이름을 바꾸는 것)으로 불리는 것으로, 클래스의 확장 시 메서드의 충돌없는 오버라이드를 위해 만들어진 것이라고 한다.
# 이를 private 효과를 본다고 생각하면 안되며, 일부 오류(부작용)를 초래할 수 있기 때문에 파이썬에서는 객체의 인터페이스 용도(접근 용도)가 아닌 속성(또는 메서드)에는 밑줄(_) 두 개가 아닌 하나를 붙여주는 것이 좋다.
▶ 밑줄(_) 한 개와 두 개의 차이, 그리고 접근 여부와 방법 테스트 #1
class InfoHiding:
def __init__(self):
self.public_value = 1
self._protected_value = 2
self.__private_value = 3
def _protected(self):
print('_protected 입니다.')
def __private(self):
print('__private 입니다.')
h1 = InfoHiding()
print(h1.__dict__)
# {'public_value': 1, '_protected_value': 2, '_InfoHiding__private_value': 3}
# "__private_value" 속성명은 "_InfoHiding__private_value"로 변경됨(파이썬 내부적으로 사용)
h1.public_value += 1
h1._protected_value += 1
#h1.__private_value += 1 # 오류 발생
# AttributeError: 'InfoHiding' object has no attribute '__private_value'
# 변수 앞에 "__"가 있는 것은 외부에서 접근 불가
print(h1.public_value) # 2
print(h1._protected_value) # 3
#print(h1.__private_value)
# AttributeError: 'InfoHiding' object has no attribute '__private_value'
print(h1.__dict__)
# {'public_value': 2, '_protected_value': 3, '_InfoHiding__private_value': 3}
# "__private_value" 제외한 2개의 속성(변수)는 접근 가능하여 값이 수정됨
h1.public_value = 10
h1._protected_value = 20
h1.__private_value = 30
print(h1.__dict__)
# {'public_value': 10, '_protected_value': 20, '_InfoHiding__private_value': 3, '__private_value': 30}
# 2개의 속성(변수)값이 수정되었고, "__private_value" 속성이 추가됨 (정보은닉된 속성 아님)
print(h1.public_value) # 10
print(h1._protected_value) # 20
print(h1.__private_value) # 30
print(h1._InfoHiding__private_value) # 3
h1._protected() # _protected 입니다.
#h1.__private() # 오류 발생
# AttributeError: 'InfoHiding' object has no attribute '__private'
h1._InfoHiding__private() # __private 입니다.
▶ 밑줄(_) 한 개와 두 개의 차이, 그리고 접근 여부와 방법 테스트 #2
# 객체 내에 있는 attribute, method 앞에 밑줄 두 개('__' double underscore)를 붙이면 객체 외부에서 해당 이름으로 접근할 수 없게 된다.
class Person2:
def __init__(self, n, a):
self.__name = n
self.__age = a
def __str__(self):
return '{0}: {1}'.format(self.__name, self.__age)
def main():
p = Person2('James', 22)
print(p) # James: 22 --> __str__ 호출 결과
#p.__age += 1 # AttributeError: 'Person2' object has no attribute '__age'
#print(p)
print(dir(p))
print(p.__dict__)
# {'_Person2__name': 'James', '_Person2__age': 22}
p.__dict__['__name'] = 'Choi' # __name 속성값 수정 시도
# _Person2__name이 아닌 해당 객체의 변수로 추가됨(주어진 값 할당됨)
print(p.__dict__)
# {'_Person2__name': 'James', '_Person2__age': 22, '__name': 'Choi'}
print(p) # James: 22
print(p.__name) # Choi --> p 객체의 변수값
print(dir(p))
main()
※ attribute, method 앞에 __(double underscore)를 붙이면, 해당 이름이 "_Classname__속성명 또는 메소드명"으로 변경됨
※ __(double underscore)가 붙은 변수(속성)값 수정하려고 할 경우, 본래 목적이 아닌 해당 객체의 변수로 추가됨
▶ print(dir(p)) --> p.__dict__['__name'] = 'Choi' 하기 전
['_Person2__age', '_Person2__name', '__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', __weakref__']
▶ print(dir(p)) --> p.__dict__['__name'] = 'Choi' 한 후
['_Person2__age', '_Person2__name', '__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__name', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__']
[참고 자료] 윤성우의 열혈파이썬 중급편
'코딩 연습 > 코딩배우기' 카테고리의 다른 글
[python] 파이썬 property객체, @property 데코레이터 (0) | 2020.09.14 |
---|---|
[python] 파이썬 __slots__의 효과 (0) | 2020.09.14 |
[python] 파이썬 __str__ 메서드에 대해 (0) | 2020.09.13 |
[python] 파이썬 __init__, __str__, __iter__, __next__ 등의 메서드 (0) | 2020.09.12 |
[python] 파이썬 파일 쓰기, 읽기 - open(), read(), readline(), readlines() (0) | 2020.09.11 |
댓글