고려대학교 지능정보 SW 아카데미 4기/정리노트

[Python] class의 __new__, __init__인자 에러

2realzoo 2024. 3. 15. 08:52

 

__new__, __init__사용

class A:
  def __new__(self):
    print('new')
  def __init__(self, x):
    print('init')

 wa = A()
 #new

 print(wa)
 #none

 

__new__에서 인스턴스를 생성해 반환하지 않고 있으므로 __init__이 실행되지 않았을 뿐더러 waNone이다.

 

오류 1.


__init__에 인자 x를 주었을 때

class AA(metaclass=type): #metaclass 속성에 type 따로 넣는 것
  def __new__(cls): #생성 관련 부분
    print('new')
    return super().__new__(cls)
  def __init__(self, x): #초기값 주는 부분
    print('init')

a = AA()

 

AA의 인스턴스 a를 만드는 부분에서 에러가 발생하였다.

new
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-5-293bd2c67928> in <cell line: 1>()
----> 1 a = AA()

TypeError: AA.__init__() missing 1 required positional argument: 'x'

 

__new__의 동작 방식을 잘 몰랐기 때문에 왜 에러가 났는지 알 수 없었다.
__new__는 클래스 객체를 호출해 인스턴스화 할 떄 호출되며 그 반환값을 __init__의 첫번째 인자인 self로 반환한다.
첫번째 예제에서는 None을 반환하였기 때문에 인스턴스가 생성되지 않았다.
오류 1에서는 자기자신을 super()을 통해 type.__new__ 의 인자로 전달하였기 때문에 __init__이 호출되었다.
하지만 __init__의 인자가 selfx 두개 필요하므로 에러가 발생한 것이다.

 

오류 2.


그렇다면 클래스AA에 인자를 전달하며 인스턴스화를 진행한다면 어떻게 될까?

a = AA(1)
TypeError                                 Traceback (most recent call last)
<ipython-input-6-c4b3379fea05> in <cell line: 1>()
----> 1 a = AA(1)

TypeError: AA.__new__() takes 1 positional argument but 2 were given

 

이번엔 __new__에서 에러가 발생하는 것을 확인할 수 있다.
__new__는 인자를 하나만 받도록 되어있는데, cls는 숨겨진 파라미터로 받아지기 때문에 두개의 인자가 들어왔다고 하는 에러가 뜬 것이다.


그래서

 

해결

class AA(metaclass=type): #metaclass 속성에 type 따로 넣는 것
  def __new__(cls, x): #생성 관련 부분
    print('new')
    return super().__new__(cls)
  def __init__(self, x): #초기값 주는 부분
    print('init')

a = AA(1)

 

__new____init__의 parameter 수를 맞추어 주고, 인스턴스 생성 시 argument를 넣어주니 오류가 나지 않았다.

이때 사용할 수 있는 것이 가변 포지셔닝, 가변 키워드 파라미터이다.

 

class AA(metaclass=type): 
  def __new__(cls, *args, **kwargs): #생성 관련 부분
    print('new')
    return super().__new__(cls)
  def __init__(self, *args, **kwargs): #초기값 주는 부분
    print('init')

a = AA(1)
a = AA()
#new
#init

 

이를 사용하면 어떤 argument를 넣어도 에러가 나지 않고 실행된다.