[python] 파이썬에서 속성 기능을 사용하는 방법에 대한 실제 예?

@property파이썬 에서 사용하는 방법에 관심이 있습니다 . 나는 파이썬 문서를 읽었으며 그 의견은 장난감 코드 일뿐입니다.

class C(object):
    def __init__(self):
        self._x = None

    @property
    def x(self):
        """I'm the 'x' property."""
        return self._x

    @x.setter
    def x(self, value):
        self._x = value

    @x.deleter
    def x(self):
        del self._x

_x속성 데코레이터로 채워서 어떤 이점을 얻을 수 있는지 모르겠습니다 . 왜 다음과 같이 구현하지 않습니까?

class C(object):
    def __init__(self):
        self.x = None

속성 기능은 일부 상황에서 유용 할 수 있다고 생각합니다. 하지만 때? 누군가 제게 실제 사례를 알려 주시겠습니까?

감사.



답변

다른 예로는 집합 속성의 유효성 검사 / 필터링 (한계 또는 수용 가능) 및 복잡하거나 빠르게 변하는 용어에 대한 게으른 평가가 있습니다.

속성 뒤에 숨겨진 복잡한 계산 :

class PDB_Calculator(object):
    ...
    @property
    def protein_folding_angle(self):
        # number crunching, remote server calls, etc
        # all results in an angle set in 'some_angle'
        # It could also reference a cache, remote or otherwise,
        # that holds the latest value for this angle
        return some_angle

>>> f = PDB_Calculator()
>>> angle = f.protein_folding_angle
>>> angle
44.33276

확인:

class Pedometer(object)
    ...
    @property
    def stride_length(self):
        return self._stride_length

    @stride_length.setter
    def stride_length(self, value):
        if value > 10:
            raise ValueError("This pedometer is based on the human stride - a stride length above 10m is not supported")
        else:
            self._stride_length = value


답변

하나의 간단한 유스 케이스는 읽기 전용 인스턴스 속성을 설정하는 것 _x입니다. 파이썬에서 하나의 밑줄 로 변수 이름을 가져 오는 것은 보통 개인용 (내부 사용)을 의미하지만 때로는 인스턴스 속성을 읽고 쓸 수는 없습니다. 우리는 property이것을 위해 사용할 수 있습니다 :

>>> class C(object):

        def __init__(self, x):
            self._x = x

        @property
        def x(self):
            return self._x

>>> c = C(1)
>>> c.x
1
>>> c.x = 2
AttributeError        Traceback (most recent call last)

AttributeError: can't set attribute


답변

매우 실용적 으로이 기사 를 살펴보십시오 . 간단히 말해서, 파이썬에서 보통 명시적인 getter / setter 메소드를 버릴 수있는 방법을 설명합니다. 어떤 단계에서 필요하다면 property매끄러운 구현에 사용할 수 있기 때문 입니다.


답변

내가 사용했던 한 가지는 데이터베이스에 저장된 느리게 보이지만 변경되지 않는 값을 캐싱하는 것입니다. 이것은 속성이 계산이나 요구가 많은 다른 긴 작업 (예 : 데이터베이스 확인, 네트워크 통신)이 필요한 상황을 일반화합니다.

class Model(object):

  def get_a(self):
    if not hasattr(self, "_a"):
      self._a = self.db.lookup("a")
    return self._a

  a = property(get_a)

이것은 웹 페이지에서 주어진 페이지보기 가이 종류의 특정 속성을 하나만 필요로하지만 기본 객체 자체에는 여러 가지 속성이있을 수 있습니다. 시공시 모두 초기화하면 낭비가되며 속성을 사용하면 유연 할 수 있습니다 속성은 게으르고 그렇지 않습니다.


답변

답변과 의견을 읽으면 주요 주제는 답변이 간단하지만 유용한 예가 누락 된 것 같습니다. 여기에 @property데코레이터 의 간단한 사용법을 보여주는 매우 간단한 것이 포함되어 있습니다 . 사용자가 다양한 단위 (예 : in_feet또는)를 사용하여 거리 측정을 지정하고 얻을 수있는 클래스입니다 in_metres.

class Distance(object):
    def __init__(self):
        # This private attribute will store the distance in metres
        # All units provided using setters will be converted before
        # being stored
        self._distance = 0.0

    @property
    def in_metres(self):
        return self._distance

    @in_metres.setter
    def in_metres(self, val):
        try:
            self._distance = float(val)
        except:
            raise ValueError("The input you have provided is not recognised "
                             "as a valid number")

    @property
    def in_feet(self):
        return self._distance * 3.2808399

    @in_feet.setter
    def in_feet(self, val):
        try:
            self._distance = float(val) / 3.2808399
        except:
            raise ValueError("The input you have provided is not recognised "
                             "as a valid number")

    @property
    def in_parsecs(self):
        return self._distance * 3.24078e-17

    @in_parsecs.setter
    def in_parsecs(self, val):
        try:
            self._distance = float(val) / 3.24078e-17
        except:
            raise ValueError("The input you have provided is not recognised "
                             "as a valid number")

용법:

>>> distance = Distance()
>>> distance.in_metres = 1000.0
>>> distance.in_metres
1000.0
>>> distance.in_feet
3280.8399
>>> distance.in_parsecs
3.24078e-14


답변

속성은 특정 필드를 조작하고 미들웨어 계산을 수행 할 수있는 방법을보다 세밀하게 제어 할 수있는 필드 주변의 추상화입니다. 기억에 남는 사용법 중 일부는 유효성 검사와 사전 초기화 및 액세스 제한입니다.

@property
def x(self):
    """I'm the 'x' property."""
    if self._x is None:
        self._x = Foo()

    return self._x


답변

예, 게시 된 원래 예제의 경우 속성은 단순히 인스턴스 변수 ‘x’를 갖는 것과 정확히 동일하게 작동합니다.

이것은 파이썬 속성에 대한 가장 좋은 것입니다. 외부에서는 인스턴스 변수와 똑같이 작동합니다! 클래스 외부에서 인스턴스 변수를 사용할 수 있습니다.

이것은 첫 번째 예제가 실제로 인스턴스 변수를 사용할 수 있음을 의미합니다. 상황이 변경 된 다음 구현을 변경하기로 결정하고 속성이 유용한 경우 속성에 대한 인터페이스는 클래스 외부의 코드와 동일합니다. 인스턴스 변수에서 속성으로 변경해도 클래스 외부의 코드에는 영향을 미치지 않습니다.

다른 많은 언어와 프로그래밍 과정에서는 프로그래머가 인스턴스 변수를 노출하지 말고 클래스 외부에서 액세스 할 수있는 ‘getters’및 ‘setters’를 사용하십시오 (질문에 인용 된 간단한 경우도).

많은 언어 (예 : Java)를 사용하는 클래스 외부의 코드

object.get_i()
    #and
object.set_i(value)

#in place of (with python)
object.i
    #and 
object.i = value

그리고 클래스를 구현할 때 첫 번째 예제와 정확히 같은 많은 ‘getter’와 ‘setter’가 있습니다. 단순히 인스턴스 변수를 복제하십시오. 클래스 구현이 변경되면 클래스 외부의 모든 코드를 변경해야하므로 이러한 getter 및 setter가 필요합니다. 그러나 파이썬 속성은 클래스 외부의 코드가 인스턴스 변수와 동일하도록 허용합니다. 따라서 속성을 추가하거나 간단한 인스턴스 변수가 있으면 클래스 외부의 코드를 변경할 필요가 없습니다. 따라서 대부분의 객체 지향 언어와 달리 간단한 예제 에서는 실제로 필요하지 않은 ‘getter’및 ‘setter’대신 인스턴스 변수를 사용할 있으며 나중에 속성으로 변경하면 코드를 사용한다는 사실을 알고 있습니다. 수업은 변경할 필요가 없습니다.

즉, 복잡한 동작이있는 경우에만 속성을 작성해야하며, 질문에 설명 된대로 간단한 인스턴스 변수 만 있으면 인스턴스 변수를 사용할 수있는 매우 일반적인 간단한 경우에 해당합니다.