서문
프로퍼티는 프로퍼티를 메서드 집합에 연결하는 역할을 하는 기본 제공 설명자 유형을 제공합니다.
프로퍼티는 4개의 선택적 인수를 허용합니다. 마지막 인수는 프로퍼티에 연결된 문서 문자열을 정의하는 데 사용할 수 있습니다.
코드
다음은 두 개의 정점을 보유하는 프로퍼티에 직접 액세스하는 메서드와 너비와 높이를 호출하는 메서드, 두 가지 제어 메서드가 있는 Rectangle 클래스를 빌드하는 방법입니다.
class Rectangle:
def __init__(self, x1, y1, x2, y2):
self.x1, self.y1 = x1, y1
self.x2, self.y2 = x2, y2
def _width_get(self):
return self.x2 - self.x1
def _width_set(self, value):
self.x2 = self.x1 + value
def _height_get(self):
return self.y2 - self.y1
def _height_set(self, value):
self.y2 = self.y1 + value
width = property(
_width_get, _width_set,
doc="rectangle width measured from left"
)
height = property(
_height_get, _height_set,
doc="rectangle height measured from top"
)
def __repr__(self):
return "{}({}, {}, {}, {})".format(
self.__class__.__name__,
self.x1, self.y1, self.x2, self.y2
)
가장 먼저 알아야 할 것은 직사각형은 대각선의 두 꼭지점에서 결정될 수 있다는 전제이므로 초기화할 때 두 꼭지점의 좌표를 전달합니다.
width_get의 목적은 정점을 기준으로 직사각형의 너비를 구하는 것이고, _width_set은 첫 번째 정점을 기준으로 두 번째 정점의 값을 수정하여 직사각형의 너비를 수정하는 것입니다. 높이_get과 _height_set의 사용법은 위와 동일합니다.
그런 다음 이 속성을 사용하여 너비와 높이 두 속성을 만듭니다. 너비의 경우, 예를 들어 _width_get, _width_set, 해당 속성 매개변수는 fget 및 fset이며, 문서의 매개변수는 속성에 대한 설명입니다.
이 프로퍼티가 정의되면 너비/높이에 액세스하여 길이를 가져올 때마다 _width_get/_height_get이 호출되고, 너비/높이에 값을 할당하여 두 번째 버텍스의 값을 설정할 때 _width_set/_height_set이 호출됩니다.
Rectangle 클래스 객체를 사용할 때 인스턴스화된 객체에 대한 정보를 표시하는 데 사용되는 __repr__ 메서드도 클래스 내에 있습니다.
테스트
rectangle = Rectangle(10, 10, 25, 34)
print(rectangle.width, rectangle.height)
rectangle.width = 100
print(rectangle)
rectangle.height = 100
print(rectangle)
실행 결과는 다음과 같습니다.
15 24
Rectangle(10, 10, 110, 34)
Rectangle(10, 10, 110, 110)
너비와 높이에 액세스하면 자동으로 계산이 수행되고 너비와 높이에 값을 할당할 때 첫 번째 점의 좌표는 변경되지 않고 두 번째 점은 할당된 값에 따라 수정되는 것을 볼 수 있습니다.
도움말을 사용하여 수업을 살펴보세요.
help(Rectangle)
실행 결과는 다음과 같습니다:
Help on class Rectangle in module __main__:
class Rectangle(builtins.object)
| Rectangle(x1, y1, x2, y2)
|
| Methods defined here:
|
| __init__(self, x1, y1, x2, y2)
| Initialize self. See help(type(self)) for accurate signature.
|
| __repr__(self)
| Return repr(self).
|
| ----------------------------------------------------------------------
| Data descriptors defined here:
|
| __dict__
| dictionary for instance variables (if defined)
|
| __weakref__
| list of weak references to the object (if defined)
|
| height
| rectangle height measured from top
|
| width
| rectangle width measured from left
너비와 높이 및 이에 대한 설명을 볼 수 있습니다.
위험 및 개선 사항
위의 접근 방식은 프로퍼티가 디스크립터 작성을 단순화하지만 현재 클래스의 메서드를 사용하여 실시간으로 생성되고 클래스 상속을 사용할 때 하위 클래스에서 재정의된 메서드는 사용되지 않으므로 위험할 수 있습니다.
예를 들어 다음 예는 다음과 같습니다.
class MetricRectangle(Rectangle):
def _width_get(self):
return "{} meters".format(self.x2 - self.x1)
print(MetricRectangle(0, 0, 100, 100).width)
여기서 얻는 실행 결과는 예상되는 수정된 결과가 아니라 그대로이며, 수정을 구현하려면 전체 프로퍼티를 다시 작성해야 합니다.
class MetricRectangle(Rectangle):
def _width_get(self):
return "{} meters".format(self.x2 - self.x1)
width = property(_width_get, Rectangle.width.fset)
print(MetricRectangle(0, 0, 100, 100).width)
프로퍼티를 데코레이터로 사용하기
프로퍼티를 생성하는 가장 좋은 구문은 프로퍼티를 데코레이터로 사용하는 것입니다. 이렇게 하면 클래스 내부의 메서드 수가 줄어들고 코드의 가독성과 유지 관리성이 향상됩니다.
class Rectangle:
def __init__(self, x1, y1, x2, y2):
self.x1, self.y1 = x1, y1
self.x2, self.y2 = x2, y2
@property
def width(self):
"""rectangle height measured from top"""
return self.x2 - self.x1
@width.setter
def width(self, value):
self.x2 = self.x1 + value
@property
def height(self):
"""rectangle height measured from top"""
return self.y2 - self.y1
@height.setter
def height(self, value):
self.y2 = self.y1 + value
하지만 이 방법의 문제점은 클래스 상속에서는 일부가 아닌 전체 프로퍼티를 수정해야 할 때만 다시 작성할 수 있다는 것입니다.





