2015-01-08 2 views
2

속성의 속성을 설정하는 사람이 최상위 클래스에서 일부 동작을 트리거하는 방법을 파악하려고합니다.속성의 속성 설정

예를 들어, 내 최상위 클래스가 Segment이라고 가정 해 보겠습니다. 이 객체의 속성으로 종점의 좌표를 직접 저장하는 경우 모두 좋음 x0, y0, x1y1 및 각 셋터가 선택한 동작을 트리거하도록합니다. 나는 특성이 좌표 중 하나가 수정 될 때마다 p0p1, 속성 xy 각각 같은 두 Point 회원으로 그룹화하려는 경우

는하지만, 뭔가를 할 수 Segment를 말하는 명백한 방법이 없습니다. 이것은 내가 할 수있을 싶은 것이 있습니다 :

>>> segment = Segment(Point(0, 0), Point(3, 3)) 
>>> segment.p0 
Point(0, 0) 
>>> segment.p0.x 
0 
>>> segment.p1.y = 4 
Length of segment changed to 5.0! # This can only be printed by segment, not p1! 

문제는 그 라인 segment.p1.y = 4 첫 통화량 segment 인스턴스 p1의 게터 다음 이전 호출의 반환에 y의 세터 , 변경이 이루어진 것을 segment 인스턴스에 알리는 간단한 방법은 없습니다. 이것은 내가, 내가 꽤 수동으로 다시 링크를 추가 할 필요 같은 수행 할 작업을 수행하는 동안

class Point(object): 
    def __init__(self, x, y, parent=None, name=None): 
     self.parent, self.name = parent, name 
     self._x, self._y = x, y 

    @property 
    def x(self): 
     return self._x 
    @x.setter 
    def x(self, value): 
     self._x = value 
     if parent is not None: 
      setattr(self.parent, self.name, self) 

    # Similar code for y goes here... 


class Segment(object): 
    def __init__(self, p0, p1): 
     self.p0, self.p1 = p0, p1 

    @property 
    def p0(self): 
     return self._p0 
    @p0.setter 
    def p0(self, point): 
     self._p0 = point 
     self.p0.parent = self 
     self.p0.name = 'p0' 
     if not self._silent: 
      self.do_something() # This would print the length in the above example 

    # Similar code for p1 goes here... 

:

지금 내가 생각할 수있는 최선은 다음의 라인을 따라 뭔가 부모에게,도 내가 어떻게 Point 객체의 중복 사본 또는 위험 재미있는 버그를 많이 만드는 것 중 하나 같은 일을하는 경우 :

p0, p1, p2 = Point(0, 0), Point(1, 1), Point(2, 2) 
seg0 = Segment(p0, p1) 
seg1 = Segment(p0, p2) 
# The following line changes the value on both seg0 and seg1, but triggers 
# the do_something call on seg1 only! 
seg0.p0.x = 6 

일부 기성 조리법이 거기인가를? 누구나 그것을 할 수있는 더 좋은 방법을 생각해 낼 수 있습니까? 아마도

답변

2

당신은 Observer design pattern를 찾고 있습니다 :

import math 

class Point(object): 
    def __init__(self, x, y, name=None): 
     self.name = name 
     self._x, self._y = x, y 
     self.observers = [] 

    def observe(self, observer): 
     self.observers.append(observer) 

    def __repr__(self): 
     return 'Point({}, {})'.format(self.x, self.y) 

    @property 
    def x(self): 
     return self._x 
    @x.setter 
    def x(self, value): 
     self._x = value 
     for o in self.observers: 
      o.notify() 

    @property 
    def y(self): 
     return self._y 
    @y.setter 
    def y(self, value): 
     self._y = value 
     for o in self.observers: 
      o.notify() 

class Segment(object): 
    def __init__(self, p0, p1): 
     self._p0, self._p1 = p0, p1 
     p0.observe(self) 
     p1.observe(self) 

    def __repr__(self): 
     return 'Segment({}, {})'.format(self.p0, self.p1) 

    def notify(self): 
     print('Length of {} changed to {}'.format(self, self.length())) 

    def length(self): 
     return math.sqrt((self.p0.x - self.p1.x)**2 
         + (self.p0.y - self.p1.y)**2) 

    @property 
    def p0(self): 
     return self._p0 
    @p0.setter 
    def p0(self, point): 
     self._p0 = point 

    @property 
    def p1(self): 
     return self._p1 
    @p1.setter 
    def p1(self, point): 
     self._p1 = point 

segment = Segment(Point(0, 0), Point(3, 3)) 
print(segment.p0) 
# Point(0, 0) 
print(segment.p0.x) 
# 0 
segment.p1.y = 4 

수익률

Length of Segment(Point(0, 0), Point(3, 4)) changed to 5.0 

p0, p1, p2 = Point(0, 0), Point(1, 1), Point(2, 2) 
seg0 = Segment(p0, p1) 
seg1 = Segment(p0, p2) 
seg0.p0.x = 6 

수확량

Length of Segment(Point(6, 0), Point(1, 1)) changed to 5.09901951359 
Length of Segment(Point(6, 0), Point(2, 2)) changed to 4.472135955 
+0

확실히 감사합니다. 감사합니다. GOF 책을 재검토 할 시간, 이번에는 실제로 그것에주의를 기울입니다 ... – Jaime