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와 오버라이딩의 동작을 잊지 않도록 해야겠다.