2014년 8월 27일 수요일

[Python] 클래스 오브젝트 생성 제어

좀 특별한 경우겠지만, 특정 클래스의 오브젝트를 생성 할 때 조건을 만족하지 않으면 생성되지 않고 None이 되게 하고 싶은 경우라고 가정하자. 이렇게 하면 클래스 오브젝트 생성을 이용해 밸리데이션(Validation)이 가능해진다.

하지만 파이썬의 클래스 생성자격인 __init__ 은 값을 리턴 할 수가 없다. (정확히는 None만 리턴이 가능하다) 사실 대부분의 OOP에서 클래스의 생성자는 리턴을 가질 수 없다. Objective-C 같이 특이한 경우를 제외하고는...

이런 경우를 위해서 파이썬 최상위 클래스인 object에 __new__ 라는게 준비되어 있다. 한번 더 이야기하지만, object에 정의가 되어있다. 즉 object를 상속받아야만 동작한다.

아래의 클래스 예제를 보자.
class SomeClass(object):
    string1 = None
    string2 = None

    def __new__(cls, *args, **kwargs):
        if len(args) < 2: return None
        return super(SomeClass, cls).__new__(cls, *args, **kwargs)

    def __init__(self, string1=None, string2=None):
        self.string1 = string1
        self.string2 = string2

    def __repr__(self):
        return 'string1 = {}, string2 = {}'.format(self.string1, self.string2)

분명하게 object를 상속받고 있다. 그리고 __new__ 라는 메소드를 정의하고 있다.

위 예제에서 __new__는 이름없는 파라미터 갯수가 2개 보다 적으면 None을 리턴하도록 하고 있다. 그 이외에는 뭔가 복잡해 보이지만, 정상적으로 클래스 오브젝트를 생성시키는 코드다.

이 클래스를 테스트 해 보자.
>>> a = SomeClass()
>>> a
>>> b = SomeClass('a', 'b')
>>> b
string1 = a, string2 = b
a와 b 두 개의 변수에 앞서 선언한 SomeClass의 오브젝트를 만드려고 하고 있다. 하지만 a는 생성되지 않았고 b는 생성되었다.

여기서 SomeClass는 오브젝트 생성 시 반드시 파라미터 값이 None이 아닌 값으로 두 개가 지정되어야 한다고 제한한다고 정리할 수 있다.

호출 순서로 보면 __new__ 가 당연히 먼저 호출 될 것이다. 여기서 두 번째 줄의 리턴문처럼 super 즉 부모클래스인 object의 __new__를 호출하도록 해야 실제로 해당 클래스가 생성되고 __init__이 호출된다.

자칫 잘못 생각하면 헷갈릴 수도 있는데, __new__에 전달되는 파라미터들은 __init__과는 별개이다. 만약 생성자를 여러 종류로 오버로드 해 놓았는데 이걸 __new__에 전달되는 것들과 혼동하면 안된다. :-)

물론 위 코드는 __new__ 에서 args의 갯수만 측정하기 때문에 파라미터에 이름을 붙여서 넘기면 의도대로 동작하지 않는다.

참고로 아는 사람은 알겠지만, __new__에 전달되는 args와 kwargs는 클래스 생성 시 넘기는 파라미터 정보가 들어오게 된다.
  • args: 이름 없는 파라미터들은 여기에 튜플로 전달된다. 위 테스트 코드의 두 번째 예제라면 ('a', 'b') 가 들어온다.
  • kwargs: 이름 붙인 파라미터들은 여기에 사전(dict)으로 전달된다. 만약 위에서 SomeClass(string1='a', string2='b')와 같은 방식으로 오브젝트를 생성하려 하면 kwargs에 { 'string1': 'a', 'string2': 'b' } 이런 데이터가 전달된다.

댓글 없음 :