TIL(Today I Learn)

인스턴스, self, 오버라이딩(Overriding) 이젠 좀 알자!

다문다뭉 2025. 7. 28. 23:38

1. 클래스와 인스턴스의 관계

  • 클래스는 설계도, 인스턴스는 그 설계도로 만든 실제 객체(실체).
  • 예를 들어, class Dog는 “강아지”라는 설계도, mydog = Dog()는 실제로 만들어진 “한 마리 강아지”다.

2. 상속(부모-자식 클래스)에서의 함수 호출 흐름

  • 자식 클래스(facade)가 부모 클래스(AOSM)를 상속받을 때, 부모만 가진 함수를 호출하면 당연히 부모의 함수가 실행된다.
  • 그런데 부모의 함수 안에서 또 다른 함수를 호출할 때 만약 그 함수가 자식에서 오버라이딩(재정의)되어 있다면,
    자식의(오버라이딩된) 함수가 호출
    된다!

3. 내가 직접 경험한 코드 히스토리

  • Facade 클래스는 AOSM(부모 클래스)을 상속.
  • 서비스 실행 과정에서 g_facade.open()을 호출하면, 내부적으로 부모의 run() 함수가 실행된다.
  • 이때, 부모의 run 안에서 self.enter()를 호출하게 되는데,
    self는 실제로 Facade 인스턴스이므로 오버라이딩된 Facade.enter()가 실행된다!
  • 즉, 부모 코드 안에서 self.xxx()처럼 메서드를 호출하면 실제 객체(=인스턴스)의 타입에 따라 자식 쪽의 함수가 우선 실행된다.

4. 이 원리를 깨닫고 느낀 점

  • 상속 구조에서 self는 “실제 객체 자신”을 가리킨다.
  • 오버라이딩이 뭔지, 왜 필요한지 실전 코드에서 완벽히 이해했다.
  • “부모 함수 안에서 자식 함수가 호출될 수 있다”는 사실이 처음엔 헷갈렸지만,
    결국 self가 인스턴스 자신(자식 클래스일 수도 있음)을 가리키기 때문임을 알게 됐다.

5. 실습 코드 예시

class Parent:
    def foo(self):
        print("부모의 foo")
        self.bar()
    def bar(self):
        print("부모의 bar")

class Child(Parent):
    def bar(self):
        print("자식의 bar(오버라이딩)")

c = Child()
c.foo()
# 출력
# 부모의 foo
# 자식의 bar(오버라이딩)

6. 마무리

  • “self가 실제로 무엇을 가리키는지” 이해했다.
  • 오버라이딩, 상속, 인스턴스가 어떻게 연결되는지 이제는 정말 확실히 알겠다.

앞으로 복잡한 상속 구조를 볼 때 self와 오버라이딩의 동작을 잊지 않도록 해야겠다.