[Python] 클래스 오브젝트 생성 제어
좀 특별한 경우겠지만, 특정 클래스의 오브젝트를 생성 할 때 조건을 만족하지 않으면 생성되지 않고 None이 되게 하고 싶은 경우라고 가정하자. 이렇게 하면 클래스 오브젝트 생성을 이용해 밸리데이션(Validation)이 가능해진다.
위 예제에서 __new__는 이름없는 파라미터 갯수가 2개 보다 적으면 None을 리턴하도록 하고 있다. 그 이외에는 뭔가 복잡해 보이지만, 정상적으로 클래스 오브젝트를 생성시키는 코드다.
이 클래스를 테스트 해 보자.
여기서 SomeClass는 오브젝트 생성 시 반드시 파라미터 값이 None이 아닌 값으로 두 개가 지정되어야 한다고 제한한다고 정리할 수 있다.
호출 순서로 보면 __new__ 가 당연히 먼저 호출 될 것이다. 여기서 두 번째 줄의 리턴문처럼 super 즉 부모클래스인 object의 __new__를 호출하도록 해야 실제로 해당 클래스가 생성되고 __init__이 호출된다.
자칫 잘못 생각하면 헷갈릴 수도 있는데, __new__에 전달되는 파라미터들은 __init__과는 별개이다. 만약 생성자를 여러 종류로 오버로드 해 놓았는데 이걸 __new__에 전달되는 것들과 혼동하면 안된다. :-)
물론 위 코드는 __new__ 에서 args의 갯수만 측정하기 때문에 파라미터에 이름을 붙여서 넘기면 의도대로 동작하지 않는다.
참고로 아는 사람은 알겠지만, __new__에 전달되는 args와 kwargs는 클래스 생성 시 넘기는 파라미터 정보가 들어오게 된다.
하지만 파이썬의 클래스 생성자격인 __init__ 은 값을 리턴 할 수가 없다. (정확히는 None만 리턴이 가능하다) 사실 대부분의 OOP에서 클래스의 생성자는 리턴을 가질 수 없다. Objective-C 같이 특이한 경우를 제외하고는...
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' }
이런 데이터가 전달된다.
댓글