![[Python 정리] __init__과 __new__의 차이에 대하여](https://img1.daumcdn.net/thumb/R750x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcvnpPx%2FbtrMS3Rm9rR%2FznYvs7pwscJks2XZVf28hk%2Fimg.png)
클래스의 기본적인 생성 방법은 아래 링크의 글을 참고하면 좋을 것 같다.
https://reo91004.tistory.com/216
[파이썬 심화] 13. 클래스 정의하기
함수를 정의하는 것은 함수 객체를 만드는 것이다. 클래스를 정의하는 것도 실제 클래스를 만드는 것이다. 파이썬에서 클래스는 객체를 만드는 툴이다! 클래스를 정의하는 문장 클래스를 만드
reo91004.tistory.com
클래스와 인스턴스의 차이를 명확히 하자
정보를 찾다 보면 객체와 인스턴스를 자주 언급된다. 둘이 같은 것이라고 하는데, 정확한 차이를 알아보자.
우선 클래스로 만든 객체를 인스턴스라고 한다. 이렇게 말하면 같은 게 맞지 않나 생각이 든다.
Klass 클래스를 활용해 kls = Klass() 로 만든 객체는 kls다. 즉 kls는 객체이다.
또한 kls 객체는 Klass의 인스턴스이다.
즉 인스턴스와 객체라는 말은 어떠한 관계라는 면에서 어감이 좀 다르다. 아래 예를 보자.
kls는 인스턴스이다. 보다는
kls는 객체이다. 가 적절하다.
kls는 Klass의 객체이다. 보다는
kls는 Klass의 인스턴스이다. 가 적절하다.
결론은 둘이 의미상 같은 것이 맞지만 주술 관계에 따라 선택하는 것이 좋다.
__init__과 __new__의 차이
둘의 차이점에 대해 찾다 보면 자세하게 기술되어 있는 것 같으면서도 너무 두루뭉술해서 직접 정리해본다.
__init__은 인스턴스 초기화에 사용하는 특수 메서드다. 인스터스 초기화에 대해 짚고 넘어가보자.
인스턴스 초기화라 하면 C++나 Java 등의 생성자(Constructor)를 떠올리는 사람이 많을 수 있다. C++, Java에서는 실제로 생성자가 인스턴스 생성과 초기화 둘 다 수행하기 때문이다. 그러나 파이썬의 __init__은 인스턴스 생성 후 호출된다는 점에서 생성자와 다르다.
즉 C++/Java의 생성자는 인스턴스 생성/초기화를 수행하고, 파이썬의 __init__은 인스턴스 초기화를 수행한다.
파이썬에서 생성자에 대응하는 메서드를 찾는다면 __new__를 들 수 있다. 반환값은 해당 클래스의 인스턴스가 된다.
이는 클래스 객체를 호출해 인스턴스화를 수행할 때 __new__를 호출한 후 그 반환값을 __init__의 첫 번째 인자인 self로 반환한다고 말할 수 있다. 유의할 점은 인스턴스를 반환하지 않는다면 인스턴스화가 되지 않는다. 아래에서 다시 다룬다.
__new__는 클래스 자기 자신을 인자로 받는다. 주로 cls라고 선언한다.
class Klass:
def __new__(cls, *args): # *args로 여러 인자를 받음
print('cls :', cls) # cls 정보 출력
print('new :', args)
return super().__new__(cls) # Klass 인스턴스 반환
def __init__(self, *args): *args로 여러 인자를 받음
print('init :', args)
kls = Klass(1, 2, 3)
>>>
cls : <class '__main__.Klass'>
new : (1, 2, 3)
init : (1, 2, 3)
유의할 점은 super().__new__(cls)이다. 위에서 말했듯 해당 클래스의 인스턴스를 반환해야 하므로 부모 클래스에서 __new__를 호출하는데 자신을 인자로 주어 해당 값을 반환한다.
__new__ 사용 시 주의할 점?
사실 __new__를 사용할 일이 별로 없다. 대부분의 인스턴스 초기화는 __init__으로 해결되기 때문이다.
그러나 __new__를 활용하면 일반적인 상황에서는 할 수 없는 동작을 간단히 구현할 수 있다. 아래 코드를 보자.
class Person:
def __new__(cls, name):
if isinstance(name, str): # name을 문자열로 받았다면
return super().__new__(cls) # 이 객체의 인스턴스 반환
else:
print("문자열로 받지 않았습니다.")
return -1
def __init__(self, name):
self.name = name
print(Person(1004))
print(Person('Reo').name)
>>>
문자열로 받지 않았습니다.
-1
Reo
사람의 이름을 문자열로 받지 않았을 때 아예 객체를 반환하지 않도록 해 Person 인스턴스가 되지 않는 식으로 사용할 수 있다. 그런데 사실 __new__ 메서드 자체를 잘 사용할 일이 없는 것으로 알고 있다.
print(Person(1004).name)
>>>
문자열로 받지 않았습니다.
Traceback (most recent call last):
File "C:\Users\reo91\OneDrive\Coding Practice\P C++, Python\Python2.py", line 12, in <module>
print(Person(1004).name)
AttributeError: 'int' object has no attribute 'name'
위에서 언급했던 것처럼 Person의 인스턴스화가 진행되지 않았고, -1을 반환했기 때문에 int 객체가 name을 가지지 않는다는 오류가 나온다.
'◎ Python > 알게된 것 정리' 카테고리의 다른 글
[Python 정리] if __name__ == "__main__": 의 의미, 활용법 (2) | 2022.09.24 |
---|---|
[Python 정리] 프로퍼티, setter, 프라이빗 속성이란? (0) | 2022.09.24 |
[Python 정리] 파이썬에서의 데이터 구조 (0) | 2022.09.22 |
[Python 정리] 파이썬 all/any 함수 (0) | 2022.09.21 |
[Python 정리] 독스트링, python/python3, 빈 리스트 판별, 동적/정적 언어 (0) | 2022.09.15 |
자기계발 블로그