2025.01.06호출과 접근 차이(feat. 의식의 흐름)

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()) # 명시적인 메서드 호출

 

위 코드에서:

  1. person.age와 person.get_age()는 동일한 결과(25)를 반환
  2. age는 변수처럼 보이지만 실제로는 메서드(property)
  3. 두 방식 모두 내부적으로는 메서드를 실행하는 것

이런 특성은 캡슐화를 구현할 때 자주 활용된다고 한다.

외부에서는 변수에 접근하는 것처럼 보이지만, 실제로는 메서드가 실행되어 추가적인 로직을 수행할 수 있다.

 

 

그럼 무슨 차이가 있어? 구분할 이유가 있어?

 

 

 

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()는 값을 읽어오는 관점에서는 사실상 동일합니다.

단, 파이썬에서 이 두 방식을 구분해서 쓰는 주된 이유가 있습니다:

  1. 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의 주요 장점:

  1. 변수처럼 접근 가능 (person.age)
  2. 값 검증 등의 추가 로직 구현 가능
  3. 기존 코드를 변경하지 않고 내부 구현 변경 가능
  4. 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