> 백엔드 개발 > 파이썬 튜토리얼 > Python 흑마법 @property 데코레이터 활용 스킬 분석

Python 흑마법 @property 데코레이터 활용 스킬 분석

高洛峰
풀어 주다: 2017-01-23 14:50:32
원래의
1222명이 탐색했습니다.

@property의 용도는 무엇인가요? 표면적으로는 메소드에 속성으로 액세스하는 것입니다.
코드가 가장 명확합니다

class Circle(object):
  def __init__(self, radius):
    self.radius = radius
  
  @property
  def area(self):
    return 3.14 * self.radius ** 2
  
c = Circle(4)
print c.radius
print c.area
로그인 후 복사

area는 메소드로 정의되어 있지만 @property를 추가하면 c.area를 직접 프로퍼티로 접근할 수 있는 것을 볼 수 있습니다.
이제 질문이 옵니다. 시간 c.area가 호출되면 한 번 계산되는데 CPU를 어떻게 한 번만 계산할 수 있습니까? 이것은 게으른 속성입니다.

class lazy(object):
  def __init__(self, func):
    self.func = func
  
  def __get__(self, instance, cls):
    val = self.func(instance)
    setattr(instance, self.func.__name__, val)
    return val
  
class Circle(object):
  def __init__(self, radius):
    self.radius = radius
  
  @lazy
  def area(self):
    print 'evalute'
    return 3.14 * self.radius ** 2
  
c = Circle(4)
print c.radius
print c.area
print c.area
print c.area
로그인 후 복사

보시다시피 'evalute'는 한 번만 출력됩니다. 이전 블로그 게시물을 읽으셨다면 @lazy의 메커니즘을 잘 이해하셔야 합니다.
여기서, 게으른 클래스에는 이를 나타내는 __get__ 메소드가 있습니다. c.area가 처음 실행될 때 순서 문제 때문에 먼저 c.__dict__에서 검색합니다. 찾지 못하면 클래스 공간으로 이동하여 검색합니다. 은area() 메소드이므로 __get__에 의해 가로채어집니다.
__get__에서는 인스턴스의area() 메소드를 호출하여 결과를 계산하고 인스턴스에 동적으로 동일한 이름의 속성을 추가하고 할당합니다. 즉, c.__dict__에 추가합니다.
c를 다시 .area로 실행하고, 먼저 c.__dict__로 이동하여 찾으세요. 현재 이미 존재하기 때문에 해당 영역을 거치지 않습니다( ) 메소드 및 __get__.

참고
다음 코드 시나리오에 주의하세요.

코드 조각 1:
Python2.6 코드

class Parrot(object):
  def __init__(self):
    self._voltage = 100000
  
  @property
  def voltage(self):
    """Get the current voltage."""
    return self._voltage
  
if __name__ == "__main__":
  # instance
  p = Parrot()
  # similarly invoke "getter" via @property
  print p.voltage
  # update, similarly invoke "setter"
  p.voltage = 12
로그인 후 복사

코드 조각 2:
Python2.6 코드

class Parrot:
  def __init__(self):
    self._voltage = 100000
  
  @property
  def voltage(self):
    """Get the current voltage."""
    return self._voltage
  
if __name__ == "__main__":
  # instance
  p = Parrot()
  # similarly invoke "getter" via @property
  print p.voltage
  # update, similarly invoke "setter"
  p.voltage = 12
로그인 후 복사

코드 1과 2의 차이점은

class Parrot(object):
로그인 후 복사

python2.6에서
조각 테스트를 각각 실행합니다. 1: 예상되는 오류 메시지가 표시됩니다. AttributeError: 속성을 설정할 수 없습니다.
조각 2: 올바르게 실행

python2.6 문서를 참조하세요. @property는 읽기 전용 속성을 제공하지만 위 코드는 해당 @volt.setter를 제공하지 않습니다. 이는 스니펫 2 코드가 실행 오류를 표시하는 이유입니다. python2.6 문서에서 다음 정보를 찾을 수 있습니다.

BIF:
property([fget[, fset[ , fdel[, doc]]]])
속성 속성 반환 새로운 스타일의 클래스(객체에서 파생된 클래스)의 경우
python2.6에서는 클래스 정의 시 명확한 설명이 없으면 내장형 객체가 기본 기본 클래스가 아닌 것으로 나타났습니다(코드). 코드 조각 2), 우리가 정의한 Parrot(코드 조각 2)은 객체

를 상속하지 않으며 객체 클래스는 우리에게 필요한 @property 함수만 제공합니다.

새 스타일 클래스
객체에서 상속되는 모든 클래스입니다. 여기에는 목록 및 사전과 같은 모든 내장 유형이 포함됩니다. 새 스타일 클래스만 __slots__, 설명자, 속성 및 __getattribute__(와 같은 Python의 최신 다목적 기능을 사용할 수 있습니다. ).

동시에 다음 방법을 통해서도 확인할 수 있습니다.
Python 2.6 코드

class A:
  pass
 
>>type(A)
<type &#39;classobj&#39;>
로그인 후 복사

Python 2.6 코드

class A(object):
  pass
 
>>type(A)
<type &#39;type&#39;>
로그인 후 복사

반환된 에서 볼 수 있듯이 는 우리에게 필요한 객체 유형입니다(파이썬 3.0은 객체 클래스를 기본 기본 클래스로 사용하므로 모두 <'type'> 유형을 반환합니다)

Python 버전의 코드를 고려하기 위해 호환성에 관해 전환 기간 동안 문제가 발생하므로 클래스 파일을 정의할 때 객체를 좋은 습관으로 명시적으로 정의해야 한다고 생각합니다.

최종 코드는 다음과 같습니다.

class Parrot(object):
  def __init__(self):
    self._voltage = 100000
 
  @property
  def voltage(self):
    """Get the current voltage."""
    return self._voltage
 
  @voltage.setter
  def voltage(self, new_value):
    self._voltage = new_value
  
if __name__ == "__main__":
  # instance
  p = Parrot()
  # similarly invoke "getter" via @property
  print p.voltage
  # update, similarly invoke "setter"
  p.voltage = 12
로그인 후 복사

그리고 2.6과 3.0에서는 @property가 추가되었는데 2.5에는 이 기능이 없습니다.

더 많은 Python 흑마법 @property 데코레이터 팁 및 관련 기사를 보려면 PHP 중국어 웹사이트를 주목하세요!

관련 라벨:
원천:php.cn
본 웹사이트의 성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.
인기 튜토리얼
더>
최신 다운로드
더>
웹 효과
웹사이트 소스 코드
웹사이트 자료
프론트엔드 템플릿