5.1 접근 수준
아마 생성자 __init__의 이상한 이름이 눈에 띄었을거야? 앞으로 이런 걸 자주 보게 될 거야.
파이썬에는 클래스의 속성과 메서드에 대한 다양한 접근 수준이 있어서 데이터의 가시성과 보호를 제어하는 데 도움을 줘. 기본적인 접근 제어 메커니즘은 속성이나 메서드의 이름 앞에 하나 또는 두 개의 밑줄 (_와 __)을 사용하는 거야.
컨벤션 사용
밑줄 하나 _는 클래스나 모듈 외부에서 사용하면 안 되는 속성 및 메서드에 사용돼. 금지된 건 아니지만, 코드의 가독성과 유지 보수를 위해 지켜야 할 컨벤션이야.
밑줄 두 개 __는 정말로 비공개되고 외부에서의 의도적이거나 비의도적인 접근으로부터 보호해야 하는 속성 및 메소드에 사용돼. name mangling 메커니즘이 이를 덜 접근 가능하게 해주지만, 여전히 특별한 이름을 통해 접근 가능해.
공개 (public) 필드와 메소드
공개 속성과 메서드는 코드의 어느 곳에서나 접근 가능해. 파이썬에서 기본적으로 모든 속성과 메서드는 이름이 밑줄로 시작하지 않는 한 공개돼 있어.
class MyClass:
def __init__(self):
self.public_attribute = "I am public"
def public_method(self):
return "This is a public method"
obj = MyClass()
print(obj.public_attribute) # 가능
print(obj.public_method()) # 가능
파이썬의 접근 수준을 통해 캡슐화가 구현돼, 특히 비공개 필드와 메소드로.
5.2 비공개 필드와 메소드
보호된 (protected) 필드와 메소드
보호된 속성 및 메소드는 이름 앞에 밑줄 하나 _를 붙여서 표시하고 클래스 및 서브 클래스 내에서 내부적으로 사용하기 위해 설계돼. 이는 데이터를 클래스 외부에서 사용하지 않도록 다른 프로그래머에게 알려주는 컨벤션이야.
class MyClass:
def __init__(self):
self._protected_attribute = "I am protected"
def _protected_method(self):
return "This is a protected method"
obj = MyClass()
print(obj._protected_attribute) # 가능하지만 권장하지 않음
print(obj._protected_method()) # 가능하지만 권장하지 않음
프라이빗 (private) 필드와 메소드
파이썬에서 프라이빗 속성과 메소드는 이름 앞에 밑줄 두 개 __로 표시돼. 이 속성과 메소드는 클래스 내에서만 사용하는 것을 목적으로 하며, 그 주된 목표는 내부 구현을 숨기고 데이터를 외부의 의도치 않은 변경이나 사용으로부터 보호하는 거야.
외부 코드에서 이러한 속성과 메서드에 대한 직접적인 접근을 막기 위해 파이썬은 name mangling (이름 손상)이라는 특별한 메커니즘을 사용해. 이 메커니즘은 프라이빗 속성의 이름 앞에 클래스 이름을 프리픽스로 추가하여 자동으로 수정해 줘. 그래서 클래스 MyClass의 프라이빗 속성 __private_attribute는 내부적으로 _MyClass__private_attribute 이름으로 변환돼.
이렇게 하면 데이터에 대한 의도치 않은 접근을 방지하면서, 여전히 클래스 내부에서와의 작업을 가능하게 해줘. 하지만, "name mangling" 메커니즘이 절대적인 보호를 제공하지 않는다는 점을 명심하자 — 경험 많은 프로그래머는 수정된 이름을 사용하여 이러한 데이터에 접근할 수 있어.
실제로 어떻게 작동하는지 살펴보자:
class MyClass:
def __init__(self):
self.__private_attribute = "I am private"
def __private_method(self):
return "This is a private method"
def access_private_method(self):
return self.__private_method()
obj = MyClass()
# print(obj.__private_attribute) # 오류, 직접 접근 불가
# print(obj.__private_method()) # 오류, 직접 접근 불가
print(obj.access_private_method()) # 클래스의 공개 메서드를 통해 접근 가능
예에서 볼 수 있듯이, 프라이빗 속성이나 메서드에 대한 직접적인 접근은 오류를 발생시켜. 하지만 파이썬은 변경된 이름을 통해 여전히 접근 가능하게 해줘. 예를 들어, 프라이빗 속성에 아래와 같이 "손상된" 이름을 사용하여 접근할 수 있어:
class MyClass:
def __init__(self):
self.__private_attribute = "I am private"
obj = MyClass()
print(obj._MyClass__private_attribute) # 출력: I am private
"손상된" 이름을 통한 접근은 가능하지만, 이는 캡슐화 원칙을 위반하며 코드의 안정성에 문제를 야기할 수 있으므로 피하는 것이 좋아.
파이썬이 속성의 이름을 어떻게 변경하는지 확인하려면, 객체의 모든 사용 가능한 속성과 메소드를 표시하는 내장 함수 dir()를 사용할 수 있어:
class MyClass:
def __init__(self):
self.__private_attribute = "I am private"
obj = MyClass()
print(dir(obj)) # 객체의 모든 속성과 메서드를 표시, "손상된" 이름 포함
dir() 함수의 결과를 보면 _MyClass__private_attribute를 포함한 모든 속성과 메서드의 목록이 나타나는데, 이는 "name mangling" 메커니즘을 입증해줘.
5.3 자동 메소드 호출
생성자에 대해 작업할 때 흥미로운 점 중 하나가 있었어, __init__ 메소드가 자동으로 호출됐다는 것 말이야.
사실, 그런 상황은 상당히 많고 그에 따른 메서드도 많아. 예를 들어:
메소드 __str__
객체에 __str__ 메서드가 있으면, 객체를 문자열로 변환하려 할 때 자동으로 호출돼. 예를 들어, print()와 str() 함수를 사용할 때.
class Cat:
def __init__(self, name, age):
self.name = name
self.age = age
def __str__(self):
return f"{self.name} is {self.age} years old"
cat = Cat("Barsik", 5)
print(cat) # 출력: Barsik is 5 years old
메소드 __len__
객체에 __len__ 메소드가 있으면, 객체의 "길이"를 결정하려 할 때 자동으로 호출돼 — len() 함수가 사용돼. 예제:
class MyList:
def __init__(self, items):
self.items = items
def __len__(self):
return len(self.items)
my_list = MyList([1, 2, 3])
print(len(my_list)) # 출력: 3
이런 "내부 메소드는" 앞으로 많이 만나게 될 거야, 그런데 이들과 작업하는 게 참 즐거워. 그러니 준비하라구 :)
GO TO FULL VERSION