언더바 ( _ ) 1개, 2개 차이
Python 클래스 내부 변수와, 메소드에 대한 캡슐화 정도를 조절하기 위해 언더바(_)를 사용하는데, 언더바 1개와 2개는 그 정도가 다르다.
👉 하나의 언더바 (_) 사용
- _variable, _method()
- 비교적 약한 캡슐화 정도를 가짐
- 일반적으로 내부적으로 사용되는 변수, 메소드를 나타냄
👉 두개의 언더바 (__) 사용
- __variable, __method()
- 이중 언더바를 사용하면 이름이 자동으로 변환되어 상속시 충돌을 방지 (_클래스명__<변수, 함수명>)
- 강한 캡슐화 정도를 가짐 (외부에서 직접 접근 불가)
- 클래스 내부에서만 접근 가능
👉 예시 코드
아래 예시에서 볼 수 있 듯, 두개의 언더바(__)를 사용한 변수/메소드는 직접적으로 접근하지 못하고, 해당 클래스를 직접적으로 통해야 접근이 가능하다. (example._Example_c, example._Example_mc())
class Example:
a = "var a"
_b = "var _b"
__c = "var __c"
def ma(self):
return "method a"
def _mb(self):
return "method b"
def __mc(self):
return "method c"
example = Example()
print(dir(example)) # [ 'a', '_b', '_Example__c', 'ma', '_mb', '_Example__mc']
print(example.a) # var a
print(example._b) # var _b
# print(sample.__c) <- error
print(example.ma()) # method a
print(example._mb()) # method b
# print(sample.__mc()) <- error
print(example._Example__c) # var __c
print(example._Example__mc()) # method c
@staticmethod 데코레이터 란
클래스 객체를 생성하지 않더라도 외부에서 사용 가능하게 하는 것
일반적으로 클래스는 캡슐화의 원칙을 지켜야 하는게 일반적인데, staticmethod를 사용하는 이유는?
- 정적 메서드는 클래스, 인스턴스와 관계가 없는 경우에 사용
- 외부 호출 시 Class명.함수명 의 방식으로 읽기 쉬운 로직의 코드 생성 가능
- 객체의 상태에 의존하지 않는 동작 구현 목적 (클래스 변수, 인스턴스 변수에 독립적인 코드)
- 모듈 수준의 기능 제공과, 재사용성을 위해
- Service Layer 분리할 때 사용하기도 함
그래도 일반적으로는 캡슐화를 지키며 사용하는 것이 조금 더 올바른 방법
@property 데코레이터 란
다른 필드로부터 읽기 전용 필드(가공)에 대한 소요가 있을때 정의 하여 사용
해당 속성을 호출시 매번 접근하여 값을 (계산하여) 반환
캡슐화를 목적으로 주로 사용된다.
👉 예시 코드
class Profile:
def __init__(self, first_name:str, last_name:str):
self.first_name = first_name
self.last_name = last_name
@property
def full_name(self):
return self.first_name + self.last_name
profile = Profile("홍","길동")
print(profile.first_name) # "홍"
print(profile.last_name) # "길동"
print(profile.full_name) # "홍길동"
👉 추가 ) cached_property
property와 똑같이 읽기 전용 목적으로 사용 .
하지만 해당 계산 결과에 대해 캐시에 저장하여, 재사용됨
단 단일 프로세스 내 인스턴스 메모리 한정 공유됨
@property 를 이용한 getter / setter
일반적으로 클래스에서 변수들을 캡슐화 하여 관리하기 위해선, __변수명 으로 캡슐화 하여 사용하는데, 생성한 객체에서 캡슐화 된 private 변수를 직접 접근시에는 AttributeError 가 발생한다.
하지만 접근이 필요한 경우 @property를 이용해 getter/setter를 구현하여 접근 및 값을 수정 할 수 있다.
class Human:
def __init__(self, age: int, name: str):
self.__age = age
self.__name = name
# 일반 property 의 역할
@property
def profile(self):
return str(self.__age) + self.__name
# getter의 역할 - 캡슐화 된 객체 변수에 접근
@property
def age(self):
return self.__age
# setter의 역할 - 캡슐화 된 객체 변수에 접근
@age.setter
def age(self, age: int):
self.__age = age
human = Human(10, "홍길동")
print(human.__name) # AttributeError: 'Human' object has no attribute '__name'
print(human.profile) # 10홍길동
human.age = 20
print(human.profile) # 20홍길동
이렇게 하면
굳이 애써 __age와 같은 private 변수로 선언한 의의가 퇴색되고, 외부 접근이 age로 쉽게 가능해 지긴 하지만, setter에서 값에 대한 추가적인 validation 로직을 추가해 보완 할 수 있다.
즉 정리하면
기본적으로 캡슐화를 지향 하되, 외부에서 값의 read가 필요할 경우 property를 통해 getter로서 접근을 허용해주되,
수정이 필요할 경우 setter로 접근을 허용해주되, 값에 대한 validation을 추가로 작성
참고
'Python > Advanced' 카테고리의 다른 글
Python 코드 실행 과정 (0) | 2024.07.31 |
---|---|
[Python] 모듈과 패키지 (0) | 2024.06.22 |
[Python] Circular Import에 따른 파일 구조 개선 (0) | 2023.05.29 |
[Python] 가상환경, 패키지 관리 모듈 정리 (pyenv, pipenv, poetry, venv) (0) | 2023.02.11 |
[Python 비동기] (3) Library, Framework 특징 비교 (0) | 2023.02.09 |