SMALL
장고강의를 시작했지만, 파이썬이 부족한 나는 계속해서 파이썬에 의문이 생긴다.
정적메서드가 클래스, 인스턴스로 모두 호출 가능한데 인스턴스 변수에 접근은 안된대.
여기서 접근이 값을 읽거나 수정하는거고 호출이 실행시키는거라 설명을 들었는데
값을 보는 것과 함수 실행이 무슨 차이가 있어?
핵심 차이:
- 호출(실행)은 단순히 코드 블록을 실행하는 것
- 변수 접근은 객체의 상태를 읽거나 수정하는 것
- 정적 메서드는 객체 상태와 무관한 독립적인 기능이므로, 인스턴스 변수 접근은 제한되지만 호출은 가능
예시로 비유하면:
- 메서드 호출: 계산기의 버튼을 누르는 것 (기능 실행)
- 변수 접근: 계산기의 메모리 값을 보거나 수정하는 것 (상태 관리)
그렇다면 값을 보는 것과 기능 실행이 같은 결과를 가지고 올 수도 있겠네?
맞말이다~
class Person:
def __init__(self):
self._age = 25 # private 변수처럼 사용
# 방법 1: 변수에 직접 접근
@property
def age(self):
return self._age
# 방법 2: 메서드로 값 반환
def get_age(self):
return self._age
person = Person()
print(person.age) # 변수 접근처럼 보이지만 실제로는 property 메서드 실행
print(person.get_age()) # 명시적인 메서드 호출
위 코드에서:
- person.age와 person.get_age()는 동일한 결과(25)를 반환
- age는 변수처럼 보이지만 실제로는 메서드(property)
- 두 방식 모두 내부적으로는 메서드를 실행하는 것
이런 특성은 캡슐화를 구현할 때 자주 활용된다고 한다.
외부에서는 변수에 접근하는 것처럼 보이지만, 실제로는 메서드가 실행되어 추가적인 로직을 수행할 수 있다.
그럼 무슨 차이가 있어? 구분할 이유가 있어?
1. 의도의 명확성:
#변수 접근: 상태(데이터)를 직접 읽거나 수정
class Person:
def __init__(self):
self.name = "Kim" # 단순히 데이터 저장
#메서드 호출: 행동이나 계산을 수행
class Person:
def get_full_name(self):
return f"{self.first_name} {self.last_name}" # 계산이나 로직 수행
2. 성능 차이:
#변수 접근: 단순한 값의 읽기/쓰기
person.age = 25 # 단순 할당
current_age = person.age # 단순 읽기
#메서드 호출: 복잡한 로직 수행 가능
person.calculate_age() # 생년월일로부터 나이 계산
person.validate_age() # 나이 유효성 검사
3. 캡슐화와 유지보수
#변수 직접 접근: 캡슐화가 깨질 수 있음
class BankAccount:
def __init__(self):
self.balance = 0 # 직접 접근하면 위험할 수 있음
#메서드를 통한 접근: 캡슐화 유지
class BankAccount:
def __init__(self):
self._balance = 0
def deposit(self, amount):
if amount > 0: # 유효성 검사 가능
self._balance += amount
4. 성능과 부수효과
#변수 접근: 단순하고 빠름, 부수효과 없음
price = product.price # 단순 읽기
#메서드 호출: 추가 연산이나 부수효과 발생 가능
price = product.calculate_price() # 세금 계산, 로깅 등 부수 효과 가능
5. 프로그래밍 관례:
class Rectangle:
def __init__(self, width, height):
self.width = width # 단순한 상태 저장은 변수로
self.height = height
def calculate_area(self): # 계산이 필요한 것은 메서드로
return self.width * self.height
결론:
- 단순한 데이터 저장/접근은 변수 사용
- 계산이나 로직이 필요한 경우는 메서드 사용
- 나중에 로직이 필요할 수 있는 경우는 처음부터 메서드로 구현하는 것이 좋음
person.age와 person.get_age() 여기서 그러면 person.get_age()에 값을 넣어서 변경할 수 있어?
person.get_age()는 값을 가져오는(get) 메서드이기 때문에 값을 변경할 수는 없다.
값 변경은 별도의 set 메서드나 property setter를 통해 구현할 수 있다.
set 메서드:
class Person:
def __init__(self):
self._age = 25
# getter - 값을 가져오기
def get_age(self):
return self._age
# setter - 값을 설정하기
def set_age(self, new_age):
if 0 <= new_age <= 150: # 유효성 검사
self._age = new_age
else:
raise ValueError("Invalid age")
person = Person()
print(person.get_age()) # 25 출력
person.set_age(30) # 값 변경
print(person.get_age()) # 30 출력
property setter :
class Person:
def __init__(self):
self._age = 25
@property
def age(self):
return self._age
@age.setter
def age(self, new_age):
if 0 <= new_age <= 150:
self._age = new_age
else:
raise ValueError("Invalid age")
person = Person()
print(person.age) # 25 출력
person.age = 30 # property setter로 값 변경
print(person.age) # 30 출력
person.age와 person.get_age() 괄호에 뭔가를 넣어서 변화를 줄 수 있는 차이도 없다면
둘은 사실상 같은거 아냐?
맞습니다! person.age와 person.get_age()는 값을 읽어오는 관점에서는 사실상 동일합니다.
단, 파이썬에서 이 두 방식을 구분해서 쓰는 주된 이유가 있습니다:
- property (person.age) 사용:
class Person:
@property
def age(self):
return self._age
@age.setter # 값 변경은 이렇게
def age(self, value):
self._age = value
person = Person()
# 변수처럼 자연스러운 문법
print(person.age) # 읽기
person.age = 30 # 쓰기
메서드 (person.get_age()) 사용:
class Person:
def get_age(self):
return self._age
def set_age(self, value): # 값 변경은 이렇게
self._age = value
person = Person()
# 메서드 호출임이 명시적
print(person.get_age()) # 읽기
person.set_age(30) # 쓰기
결국 차이점은:
- property: 파이썬스러운(Pythonic) 방식, 변수처럼 자연스러운 사용
- 메서드: 전통적인 방식, 메서드임이 명시적
실제 동작은 같지만, 파이썬에서는 일반적으로 단순한 값 접근은 property 방식을 선호
property 방식이 뭐야?
Property는 파이썬에서 객체의 속성(attribute)에 접근하는 방식을 제어할 수 있게 해주는 기능인데
간단한 예시를 들자면
class Person:
def __init__(self):
self._age = 0 # 프라이빗 변수처럼 사용
@property # getter
def age(self):
return self._age
@age.setter # setter
def age(self, value):
if value < 0:
raise ValueError("Age cannot be negative")
self._age = value
# 사용 예시
person = Person()
person.age = 25 # setter 호출
print(person.age) # getter 호출, 25 출력
person.age = -5 # ValueError 발생
Property의 주요 장점:
- 변수처럼 접근 가능 (person.age)
- 값 검증 등의 추가 로직 구현 가능
- 기존 코드를 변경하지 않고 내부 구현 변경 가능
- getter/setter를 명시적으로 호출하지 않아도 됨
또한 read-only property도 만들 수 있다:
class Circle:
def __init__(self, radius):
self.radius = radius
@property
def area(self): # getter만 있고 setter는 없음
return 3.14 * self.radius ** 2
circle = Circle(5)
print(circle.area) # 면적 출력
circle.area = 50 # AttributeError 발생 (setter가 없으므로)
@property와 @property.setter의 차이가 뭐야?
@property
class Person:
def __init__(self):
self._age = 25
@property
def age(self): # getter
return self._age
person = Person()
print(person.age) # 읽기만 가능
- 읽기 전용 속성을 만듦
- 변수처럼 접근 가능 (괄호 없이)
- 값 변경은 불가능
@property.setter
class Person:
def __init__(self):
self._age = 25
@property
def age(self): # getter
return self._age
@age.setter
def age(self, value): # setter
if 0 <= value <= 150: # 유효성 검사
self._age = value
person = Person()
print(person.age) # 읽기 가능
person.age = 30 # 쓰기도 가능
- 읽기와 쓰기 모두 가능
- setter에서 유효성 검사 등 추가 로직 수행 가능
결론:
- property(getter)만 있으면 → 읽기만 가능
- property(getter)와 setter 둘 다 있어야 → 읽기/쓰기 모두 가능
- setter만 단독으로는 존재할 수 없음 (property가 먼저 정의되어야 함)
LIST
'Today I learned' 카테고리의 다른 글
2025.01.08 +99강화나무 (4) | 2025.01.08 |
---|---|
2025.01.07 ord에서 파생된 의문(ASCII 코드, 알고리즘) (4) | 2025.01.07 |
2025.01.03 파이썬 클래스의 메서드 (4) | 2025.01.03 |
WIL (5) | 2025.01.03 |
2025.01.02 깃 이그노어를 생활화 하자... (3) | 2025.01.02 |