Python 객체의 속성 접근 방법

hwstar·2024년 8월 6일

Python

목록 보기
2/2
post-thumbnail

파이썬에서 객체의 속성에 접근하는 방법에는 여러 가지가 있다.
다섯 가지 주요 방법에 대해 설명하고, 각 방법의 장단점과 사용 사례를 소개하려고한다.

1. 객체의 속성에 직접 접근

가장 간단한 방법으로, 객체의 속성에 직접 접근

예제 코드

class MyAge:
    def __init__(self, age):
        self._age = age

obj = MyAge(20)
print(obj._age)  # 출력: 20
obj._age = 30
print(obj._age)  # 출력: 30

장단점

  • 장점: 구현이 간단하고 직관적입니다.
  • 단점: 속성에 대한 캡슐화가 부족하여 외부에서 속성 값을 직접 변경할 수 있습니다.

사용 사례

  • 간단한 클래스에서 내부 속성에 직접 접근하는 경우.

2. 객체 내에 getter, setter 메서드 직접 구현

getter와 setter 메서드를 직접 구현하여 속성 접근을 제어하는 방법

예제 코드

class MyAge:
    def __init__(self, age):
        self._age = age

    def get_age(self):
        return self._age
    
    def set_age(self, age):
        if age < 0:
            raise ValueError("나이는 0보다 작을 수 없음")
        self._age = age

obj = MyAge(20)
print(obj.get_age())  # 출력: 20
obj.set_age(30)
print(obj.get_age())  # 출력: 30

장단점

  • 장점: 속성에 대한 캡슐화를 제공
  • 단점: 속성에 접근할 때마다 메서드를 호출해야한다.

사용 사례

  • 속성 값을 설정할 때 검증 로직이 필요한 경우.

3. @property 사용

@property 데코레이터를 사용하여 속성 접근을 메서드로 처리하되, 속성처럼 보이게 하는 방법

예제 코드

class MyAge:
    def __init__(self, age):
        self._age = age

    @property
    def age(self):
        return self._age
    
    @age.setter
    def age(self, age):
        if age < 0:
            raise ValueError("나이는 0보다 작을 수 없음")
        self._age = age

obj = MyAge(20)
print(obj.age)  # 출력: 20
obj.age = 30
print(obj.age)  # 출력: 30
# obj.age = -5  # ValueError: 나이는 0보다 작을 수 없음

장단점

  • 장점: 캡슐화와 사용의 편리함을 동시에 제공
  • 단점: 간단한 속성 접근 제어에는 적합하지만, 복잡한 로직에는 한계가 있을 수 있다.

사용 사례

  • 속성 값을 읽고 쓰는 동작을 캡슐화하고, 속성처럼 접근하도록 만들고 싶은 경우.
  • 기존 속성에 접근하는 코드를 변경하지않고, 해당 속성에 대한 검증 로직 추가와 같은 코드를 편리하게 작성 가능

4. 디스크립터 사용

디스크립터 클래스를 정의하고 이를 통해 속성 접근을 제어하는 방법

예제 코드

from weakref import WeakKeyDictionary

class Descriptor:
    def __init__(self):
        self.data = WeakKeyDictionary()

    def __get__(self, instance, instance_type):
        if instance is None:
            return self
        return self.data.get(instance, 0)
    
    def __set__(self, instance, value):
        if value < 0:
            raise ValueError(f"{self.name}는 0보다 작을 수 없음")
        self.data[instance] = value

class MyAge:
    age = Descriptor()
    height = Descriptor()

    def __init__(self, age, height):
        self.age = age
        self.height = height
  • Descriptor 클래스는 __get__, __set__ 모두 구현하였으므로 디스크립터로 판단된다.
  • WeakKeyDictionary 사용이유 : 각각의 유일한 MyAge 인스턴스가 Descriptor 클래스를 공유하지 않으면서 메모리 누수를 막기위함 (일반 딕셔너리에서 강한 참조 X 약한 참조 O)

장단점

  • 장점: 복잡한 속성 제어 로직을 구현할 수 있으며, 여러 클래스에서 재사용 가능
  • 단점: 구현이 조금 복잡할 있음, 여러 클래스에서 재사용할 경우 하나의 디스크립터를 공유하지 않도록 주의 필요

사용 사례

  • 속성 접근과 설정을 더욱 세밀하게 제어하고 싶은 경우.
  • 여러 클래스에서 동일한 속성 접근 로직을 재사용할 때.

5. __getattr__, __getattribute__, __setattr__ 사용

이 메서드들을 사용하여 속성 접근을 세밀하게 제어할 수 있습니다.

예제 코드

class MyAge:
    def __init__(self, age):
        self._age = age

    def __getattr__(self, name):
        return f"{name} 속성은 존재하지 않습니다.
"
    
    def __getattribute__(self, name):
        print(f"{name} 속성에 접근 중 __getattribute__ 호출됨
")
        return super().__getattribute__(name)
    
    def __setattr__(self, name, value):
        print(f"{name} 속성에 {value} 값을 설정 중
")
        self.__dict__[name] = value

obj = MyAge(10)  # _age 속성에 10 값을 설정 중
obj.age = 40     # age 속성에 40 값을 설정 중
print(obj.age)   # age 속성에 접근 중 __getattribute__ 호출됨 
 40
print(obj.non_existent_attr)  # non_existent_attr 속성에 접근 중 __getattribute__ 호출됨 
 non_existent_attr 속성은 존재하지 않습니다.

장단점

  • 장점: 모든 속성 접근을 세밀하게 제어할 수 있다.
    (속성에 접근할때, 존재하지 않는 속성에 접근할때, 값을 설정할때와 같이 해당 시기에 제어를 추가 가능)
  • 단점: 잘못 구현하면 무한 재귀 호출이 발생할 수 있다.
    (상위 클래스 object의 __getattribute__ 호출로 해결 가능)

사용 사례

  • 매우 세밀한 속성 접근 제어가 필요한 경우.
  • 속성 접근 시 추가적인 로직(예: 로깅, 검증 등)을 구현하고 싶은 경우.

이 다섯 가지 방법을 통해 파이썬에서 객체의 속성 접근을 다양하게 제어할 수 있습니다.
각 방법의 장단점과 사용 사례를 잘 이해하면, 적절한 상황에 맞는 접근 방식을 선택할 수 있을 것입니다.

0개의 댓글