협동적 클래스(Cooperative Classes) 란?

'협동적 super call'을 호출하는 다중 상속 관계에 있는 클래스들이다.


기존 클래스의 문제점

기존 클래스의 문제점을 살펴보자. 이것은 파이썬만의 문제가 아니라 대부분 객체지향 언어에서 발생할 수 있는 문제이다.


예를 들어, 어떤 클래스(A)가 주어져 있고, 서브 클래스(B)에서 슈퍼 클래스의 save 메소드를 확장하려 한다.

class A:

def save(self):

print 'A save call'

class B:

def save(self):

print 'B save call'

A.save(self)


A의 save는 A만의 자료를 저장하고 B의 save는 B만의 자료를 저장한다. 따라서 클래스 B의 save는 A.save 를 호출한다.

그러나 다이아몬드 관계인 경우 문제가 발생한다. 다음 클래스를 살펴보자.

이것을 수행하면 A의 데이터가 두 번이나 저장된다. (B에 의해 한 번, C에 의해 한 번)


위의 것을 현재 알고 있는 지식으로만 해결하면 다음과 같이 할 수 있겠다. 

즉, 어떤 클래스의 save는 자신의 정보만을 저장하는 self._save()를 호출한 후에 슈퍼 클래스의 지역 정보를 저장하는 메소드를 일일이 호출해야 한다.

해결은 되었지만, 누가 봐도 좋은 코드라고 말할 수 없다. 클래스 D는 슈퍼 클래스들의 모든 구조를 알아야 save 메소드를 작성할 수 있다. 이러한 내용은 객체지향 언어가 추구하고 있는 방향과는 상반된 것이다.

또한 코드의 이식성이 크게 떨어지며 나중에 C를 제거하거나, 또 다른 클래스 E를 슈퍼 클래스로 추가하려면 D의 코드는 다시 작성되어야 한다.



협동적 클래스를 이용한 문제 해결

앞서와 같은 문제는 super를 이용한 협동적 클래스로 해결이 가능하다.

super()는 다음과 같은 형식을 가진다.

super(class name, self).method()

의미는 슈퍼 클래스의 '메소드'를 호출하라는 것이다. 슈퍼 클래스는 여러 개가 있을 수 있다. 따라서 어떤 슈퍼 클래스를 호출하는가는 self.__class__.__mro__ 와 '클래스 이름'을 이용하여 결정된다.

를 들어, self.__class__.__mro__ 가 (w, x, y, z)이고 '클래스 이름'이 'x'일 경우 'x' 다음에 있는 'y'메소드가 호출된다.


구체적인 예)


클래스의 __mro__


super는 self.__class__.__mro__의 순서에 따라 save()를 호출한다고 했다. super는 self.__class__.__mro__에서 자신의 클래스 다음의 클래스 객체의 save를 호출한다.

예를 들어, super(C, self).save() 에서 전달된 self.__class__.__mro__가 (D, B, C, A, object) 라면, A.save(self) 를 호출한다.


단계적으로 설명:

1) d.save()에 의해서 super(D, self).save()가 호출된다. .self는 d이고 d.__class__.__mro__가 (D, B, C, A, object)이므로 super(D, self).save()에 의하여 B.save(self)가 호출된다.

2) B.save(self)에 의해서 super(B, self).save()가 호출된다. 이 때 self 는 여전히 'd'  임에 주의해야 한다. self.__class__.__mro__는 여전히 (D, B, C, A, object) 값을 가진다. 따라서, super(B, self).save()는 B 다음 클래스인 C 에서 C.save(self)를 호출한다.

3) 같은 방법으로 super(C, self).save()는 A.save(self)를 호출한다. 


이와 같이 super를 사용하면 앞서 해결할 수 없었던 슈퍼 클래스 메소드의 호출 문제를 깔끔하게 해결할 수 있다.

클래스의 전체 구조를 모르고도 단지 '슈퍼 클래스의 이러한 메소드를 호출하라' 식의 표현으로도 충분히 잘 동작하는 코드를 작성할 수 있다.


'Programming > Python' 카테고리의 다른 글

반복자(Iterator)  (0) 2013.05.09
class 메소드 관련  (0) 2013.05.08
연산자 오버로딩  (0) 2013.05.02
생성자와 소멸자  (0) 2013.05.02
class member, instance member  (0) 2013.05.02
Posted by scii
: