본문 바로가기

언어/Python

[ Python ] 클래스의 선행 참조 문제 분서과 해결 방법

반응형

파이썬에서 클래스의 "선행 참조" 문제는 클래스 정의 내부에서 해당 클래스의 이름을 참조하려고 할 때 발생할 수 있는 문제입니다. 이는 주로 클래스 내부에서 클래스 자체의 이름을 이용하여 속성이나 메서드를 정의하려 할 때 발생할 수 있습니다.

문제 설명

파이썬에서는 클래스가 정의되는 동안 그 클래스 이름은 아직 전역 심볼 테이블에 등록되지 않은 상태입니다. 그래서 클래스 정의 내부에서 그 클래스 이름을 바로 참조하려 하면 에러가 발생할 수 있습니다.

예제 1: 직접 참조 시도

class Node:
    left: Node
    right: Node

    def __init__(self, value):
        self.value = value
        self.left = None
        self.right = None

이 예제에서 Node 클래스 내부에서 Node라는 이름을 속성의 타입으로 사용하고 있습니다. 그러나 파이썬은 클래스가 완전히 정의되기 전까지는 Node라는 이름을 인식하지 못합니다. 이로 인해 NameError가 발생할 수 있습니다.

class Child(Parent):  # 아직 Parent 클래스가 정의되지 않음
    def __init__(self, name):
        self.name = name

class Parent:
    def __init__(self, child: Child):
        self.child = child

이 예제에서 Child 클래스 내부에서 Parent 클래스를 참조하고 있다. Parent 클래스를 먼저 정의해서 문제를 피할 수 있다.

해결 방법

1. 문자열로 타입 힌트를 제공

파이썬에서는 타입 힌트에서 클래스 자체를 참조해야 할 때, 그 클래스 이름을 문자열로 사용할 수 있습니다. 이를 통해 클래스가 완전히 정의되기 전에도 파이썬이 해당 이름을 인식하게 할 수 있습니다.

class Node:
    left: 'Node'
    right: 'Node'

    def __init__(self, value):
        self.value = value
        self.left = None
        self.right = None

이렇게 문자열로 감싸면 파이썬은 해당 문자열을 나중에 실제 클래스로 해석합니다.

2. Forward Reference 사용 (Python 3.7+)

Python 3.7부터는 from __future__ import annotations를 사용하여 "선행 참조"(Forward Reference)를 좀 더 명시적으로 처리할 수 있습니다.

from __future__ import annotations

class Node:
    left: Node
    right: Node

    def __init__(self, value):
        self.value = value
        self.left = None
        self.right = None

3. 참조되는 Class를 먼전 정의한다.

class Parent:  # Parent 클래스를 먼저 정의
    def __init__(self, child: 'Child'):  # Child를 문자열로 참조
        self.child = child

class Child(Parent):
    def __init__(self, name):
        self.name = name

이 기능은 타입 힌트가 실제로 사용될 때까지 평가되지 않도록 연기시킵니다. 따라서 이 코드에서는 Node라는 이름을 타입 힌트로 사용해도 문제가 없습니다.

요약

  • 클래스 내부에서 아직 정의되지 않은 클래스 이름을 참조하려 할 때 선행 참조 문제가 발생합니다.
  • 이 문제는 클래스 이름을 문자열로 사용하거나 from __future__ import annotations를 통해 해결할 수 있습니다.
  • 이 방식을 통해 파이썬의 타입 힌트를 명확하게 유지하면서도 선행 참조 문제를 회피할 수 있습니다.
반응형