명명 규칙에 의한 접근 제어
파이썬은 언어 차원에서 강제적인 접근 제어 기능을 제공하지 않지만, 명명 규칙을 통해 접근 제어 표현할 수 있다.
- public: 클래스 내부 및 외부 어디서든 접근이 가능한 속성이나 메서드이다. 변수명에 별도의 접두사를 붙이지 않는다. (예: name)
- protected: 클래스 내부 및 서브클래스(상속받은 클래스)에서만 사용해야 한다는 의미를 갖는다. 하지만 관례상일 뿐, 실제로 접근이 차단되는 것은 아니다. 단일 밑줄(_)을 접두사로 붙여 표시한다. (예: _name)
- private: 클래스 내부에서만 접근 가능하도록 의도된 속성이다. 네임 맹글링이 적용되어 외부에서 직접 접근할 수 없도록 처리된다. 다만, 이는 보안 목적이 아니라 속성명이 내부적으로 충돌하는 것을 방지하기 위해 사용된다. (예: __name)
class Person:
def __init__(self, name, age):
self.name = name # 공개 속성
self._age = age # 보호 속성 (관례상 직접 접근 지양)
self.__secret = "비밀" # 비공개 속성 (이름 맹글링 발생)
def reveal_secret(self):
return self.__secret
person = Person("홍길동", 30)
print(person.name) # 출력: 홍길동
print(person._age) # 출력: 30 (접근 가능하지만 관례상 외부에서 직접 접근하지 않음)
# print(person.__secret) # AttributeError 발생
print(person.reveal_secret()) # 출력: 비밀
print(person._Person__secret) # 출력: 비밀 (이름 맹글링으로 인해 이런 식으로 접근 가능)
Name Mangling
네임 맹글링은 파이썬에서 __(더블 언더스코어)로 시작하는 변수나 메서드의 이름을 내부적으로 변경하는 기능이다. 네임 맹글링을 사용하면 부모 클래스의 속성을 보호하여 자식 클래스에서 실수로 덮어쓰는 문제를 막을 수 있다.
__변수명 에서 _클래스명__변수명 으로 자동으로 변환된다.
Name Mangling을 사용하지 않은 예제
Parent의 age가 오버라이드된다.
class Parent:
def __init__(self):
self.age = 60 # 중요한 설정 값
def get_parent_age(self):
return self.age # 부모의 설정 값을 반환
class Child(Parent):
def __init__(self):
super().__init__()
self.age = 20 # 자식 클래스에서 같은 변수 사용 (부모 값 덮어씀)
c = Child()
print(c.get_parent_age()) # return : 20
Name Mangling을 사용한 예제
Parent의 age가 오버라이드되는 것을 방지한다.
class Parent:
def __init__(self):
self.__age = 60 # private 변수 (네임 맹글링 발생)
def get_parent_age(self):
return self.__age # 부모의 설정 값을 반환
class Child(Parent):
def __init__(self):
super().__init__()
self.__age = 20 # 자식 클래스의 독립적인 변수
c = Child()
print(c.get_parent_age()) # return : 60
print(c._Parent__age) # return : 60
print(c._Child__age) # return : 20
getter와 setter 구현
게터(getter)와 세터(setter)는 객체 속성에 접근하고 수정하는 메서드로 속성 보호 및 유효성 검사 등에 사용된다.
1. 전통적인 방식
class Person:
def __init__(self, name, age):
self._name = name
self._age = age
def get_name(self):
return self._name
def set_name(self, name):
if not name:
raise ValueError("이름은 비어있을 수 없습니다.")
self._name = name
def get_age(self):
return self._age
def set_age(self, age):
if age < 0:
raise ValueError("나이는 음수일 수 없습니다.")
self._age = age
person = Person("홍길동", 30)
print(person.get_name()) # 홍길동
person.set_age(35)
print(person.get_age()) # 35
2. @property 데코레이터 사용
@property 데코레이터는 메소드를 속성처럼 접근할 수 있게 해주는 기능이다.
class Person:
def __init__(self, name, age):
self._name = name
self._age = age
@property
def name(self):
return self._name
@name.setter
def name(self, name):
if not name:
raise ValueError("이름은 비어있을 수 없습니다.")
self._name = name
@property
def age(self):
return self._age
@age.setter
def age(self, age):
if age < 0:
raise ValueError("나이는 음수일 수 없습니다.")
self._age = age
person = Person("홍길동", 30)
print(person.name) # 홍길동
person.age = 35
print(person.age) # 35
getter만 구현하면 읽기 전용 속성으로 사용할 수 있다.
class Person:
def __init__(self, first_name, last_name):
self._first_name = first_name
self._last_name = last_name
@property
def first_name(self):
return self._first_name
@property
def last_name(self):
return self._last_name
@property
def full_name(self): # 읽기 전용 속성
return f"{self._first_name} {self._last_name}"
person = Person("홍", "길동")
print(person.full_name) # 홍 길동
person.full_name = "김 철수" # AttributeError: can't set attribute
Computed Properties
계산된 속성은 다른 속성들을 기반으로 값이 계산되는 속성으로 매번 접근할 때마다 실시간으로 계산되며, @property 데코레이터를 사용해 구현할 수 있다.
class Circle:
def __init__(self, radius):
self.radius = radius # 반지름
@property
def area(self):
return 3.14159 * self.radius ** 2 # 면적 계산 (computed property)
circle = Circle(5)
print(circle.area) # 78.53975 (반지름이 5일 때 면적)
circle.radius = 10
print(circle.area) # 314.159 (반지름이 10일 때 면적)
'python' 카테고리의 다른 글
파이썬 기초 - 메타 클래스와 추상 클래스 (0) | 2025.03.23 |
---|---|
파이썬 기초 - 메서드 유형과 매직 메서드 (0) | 2025.03.22 |
파이썬 기초 - Decorator (0) | 2025.03.20 |
파이썬 기초 - 예외처리 (0) | 2025.03.19 |
파이썬 기초 - Context Manager (0) | 2025.03.19 |
댓글