파이썬 순환 참조 ModuleNotFoundError, AttributeError
잘 작동하던 프로그램의 구조를 약간 바꿨더니 모듈을 제대로 인식하지 못하는 오류가 발생했다.
같은 코드를 메인 파일에서 곧바로 실행할 경우 정상적으로 인식되는데 프로그램 작동중 특정 모듈에서 해당 메소드를 호출하니 위와 같이 메소드를 찾지 못하거나 none값을 반환하는것이다.
검색을 해보니 'circular import' 라는 용어를 발견했다.
이 문제는 두개 이상의 모듈에서 서로가 서로를 참조할 때 발생하는 오류이다. 이러한 문제는 파이썬의 모듈 import과정을 이해하면 쉽게 해결할 수 있다.
아래와 같은 두 가지 파이썬 모듈을 생각해보자.
# module1.py
import module2
def function1():
module2.function2()
if __name__ == '__main__':
function1()
# module2.py
def function2():
print('함수2')
위와 같이 작성하고 module1.py 파일을 실행할 경우 정상적으로 작동하여 '함수2'라는 단어가 출력된다.
이제 모듈구조를 조금 바꿔보자.
# module1.py
import module2
def function1():
module2.function2()
def say_hello():
print('안녕하세요')
if __name__ == '__main__':
function1()
module2.function3()
# module2.py
import module1
def function2():
print('함수2')
def function3():
module1.say_hello()
이 상태에서 module1.py를 실행하면 맨위 사진과 같이 오류가 발생한다.
파이썬은 프로그램 실행시 모든 코드를 순서대로 읽어 모듈들을 import하여 레지스트리에 저장한다. 그 후 실제 프로그램 작동을 위한 코드가 실행되는 것이다.
위 예시의 module1.py을 실행하면 import module2가 실행되어 레지스트리에 module2가 추가된다. 곧바로 module2의 첫줄인 import module1이 실행되면서 레지스트리에 module1이 추가된다.
여기서 또 다시 import module2부터 실행이 되는데 레지스트리에 이미 module2가 있으므로 다음줄이 실행된다. function1()을 module2.function2()로 정의하기 위해 레지스트리에 저장된 module2를 참조한다. 하지만 레지스트리에 저장된 module2의 정보는 첫줄인 import module1밖에 저장되어 있지 않다. 따라서 메소드를 찾을 수 없다는 에러가 발생하는 것이다.
이 문제는 다음과 같이 모듈을 import해주는 위치만 바꿔주면 해결된다.
# module2.py
def function2():
print('function2')
def function3():
import module1
module1.say_hello()
참고자료
https://blog.mathpresso.com/python-circular-imports-e89c5bf16510