상속
객체 지향 언어의 큰 특징으로 부모 클래스가 가진 모든 속성을 자식에게 물려주는 것을 의미한다.
동일한 코드가 반복되지 않고 공통된 속성을 부모 클래스에서 관리하여 유지보수성을 높일 수 있다.
형식
class 부모클래스:
def __init__(self):
print("부모 클래스 생성자")
def 부모메서드(self):
print("부모 메서드 호출")
class 자식클래스(부모클래스):
def __init__(self):
super().__init__() # 부모 클래스 생성자 호출
print("자식 클래스 생성자")
def 자식메서드(self):
print("자식 메서드 호출")
super()
super() 은 부모 클래스의 메서드나 생성자를 호출하기 위해 사용된다.
super()를 사용하지 않고 부모클래스를 부모클래스.부모메서드로 접근할 수 있지만, 이는 유지 보수 측면에서 super()를 사용하는 것이 더 유연하다.
특히 다중 상속에서 MRO(Method Resolution Order)를 통해 안정적인 부모 메서드 호출이 가능하다.
class 부모:
def __init__(self):
print("부모 생성자")
def say_hello(self):
print("부모: 안녕하세요")
class 자식(부모):
def __init__(self):
# 부모 클래스의 __init__을 호출
super().__init__()
print("자식 생성자")
def say_hello(self):
# 부모 클래스의 say_hello를 호출
super().say_hello()
print("자식: 안녕!")
다중 상속
파이썬은 다중 상속을 지원한다.
2개 이상의 부모클래스를 상속하는 것을 의미하고, 모든 속성을 그대로 상속하고, 메서드 오버라이딩도 가능하다.
메서드 결정 순서는 클래스 속성이 __mro__에서 정의한다 (Method Resolution Order)
python 3 부터는 모든 클래스의 선언부를 명시하지 않아도 object 클래스를 묵시적으로 상속한다.
즉 파이썬은 모든 객체가 만들어질 때 object 객체가 기본적으로 만들어졌다고 보면 된다.
class A:
def greeting(self):
print("A: 안녕")
class B:
def greeting(self):
print("B: 헬로우")
class C(A, B): # A, B 둘 다 상속
pass
c = C()
c.greeting()
# 결과
# A : 안녕
메서드 결정 짓는 순서를 보고 싶다면, 해당 자식클래스.__mro__이나 해당 자식클래스.mro()으로 출력해서 볼 수 있다.
부모클래스를 클래스의 파라미터형식으로 표기가 되는데 , mro는 앞에서 뒤로 진행되는 것을 볼 수 있다.
- 다이야몬드형 다중상속
class A:
def show(self):
print("A")
class B(A):
def show(self):
print("B")
super().show()
class C(A):
def show(self):
print("C")
super().show()
class D(B, C): # 다중 상속
def show(self):
print("D")
super().show()
d = D()
d.show()
이에 대한 결과는 어떻게 될까 ? 한 번 생각해봐도 좋을 것 같다.
결과는 다음과 같다.
D
B
C
A
이 결과는 __mro__를 찍어보면 확인해 볼 수 있다. 실행되는 순서가 다음과 같다.
print(D.__mro__)
# (<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>)
자바에서는 다중 상속을 사용했던가 잠깐 생각해보게 된다.
생각해보면 사용하지 않은 것 같다. 계층적으로 확장해나갔지, 하위계층에서 여러개의 상위계층을 포함한 적이 있는가 생각해보게 된다.
class A {
void hello() { System.out.println("A"); }
}
class B extends A {
void hello() { System.out.println("B"); }
}
class C extends A {
void hello() { System.out.println("C"); }
}
// 자바에서는 아래처럼 B, C를 동시에 상속할 수 없음
class D extends B, C { // 컴파일 오류!
// 어떤 hello()를 쓸지 모호함
}
그렇다. 자바에서는 다중 상속을 지원하지 않고, 다중 구현은 지원하였다.
다이야몬드형 상속상 super 키워드의 문제가 발생하게 되기 때문이다.
interface A {
default void hello() { System.out.println("A"); }
}
interface B {
default void hello() { System.out.println("B"); }
}
class C implements A, B {
// 둘 다 hello() 가지고 있으니 오버라이딩 필요
public void hello() {
A.super.hello(); // 명시적으로 선택
}
}
다중 인터페이스를 구현하게 되면 명시적으로 어떤 인터페이스를 사용할지 명시를 해줘야 한다.
이쯤 다시 궁금해진다.
그렇다면 오버라이딩이 super()를 통해 된다면,
오버 로딩은 ?
파이썬의 오버로딩(overloading)
파이썬은 기본적으로 오버로딩을 지원하지 않는다.
똑같은 이름으로 두번 정의하면 마지막이 덮어씌워진다.
클래스에 __init__(self,name) , __init__(self) 를 정의하면, 경고등이 뜨면서
클래스 생성시에 인자 두개를 넣으면 마지막인 __init__(self)가 발동되면서
__init__() takes 1 positional argument but 2 were given 이라는 오류가 발생하게 된다.
아래에 다른 예시를 확인해보자.
def greet(name):
print("Hello", name)
def greet(name, age):
print(f"Hello {name}, you are {age} years old.")
greet("길동")
# TypeError! → 마지막에 정의된 greet()만 살아남고, 이전 greet는 덮어써짐
그렇다면 어떻게 오버로딩을 구현할까 ?
생각보다 간단한 문제였다.
파이썬의 디폴트 파라미터 또는 가변인자를 활용할 수 있다.
디폴트 파라미터 활용
def greet(name, age=None):
if age:
print(f"{name}, {age}살 반가워~")
else:
print(f"{name}, 안녕~")
greet("길동") # 길동, 안녕~
greet("길동", 30) # 길동, 30살 반가워~
*arg 활용
def greet(*args):
if len(args) == 1:
print(f"{args[0]}, 안녕~")
elif len(args) == 2:
print(f"{args[0]}, {args[1]}살 반가워~")
else :
print("이름 없음")
greet()
greet("길동")
greet("길동", 30)
*arg,**kwargs 활용
def greet(*args, **kwargs):
# 위치 인자가 1개만 들어오면: 이름만
if len(args) == 1 and not kwargs:
name = args[0]
print(f"안녕 {name}")
# 위치 인자가 2개면: 이름, 나이
elif len(args) == 2:
name, age = args
print(f"안녕 {name}, 너는 {age}살이구나")
# 키워드 인자로만 받았을 때
elif "name" in kwargs and "age" in kwargs:
print(f"안녕 {kwargs['name']}, 너는 {kwargs['age']}살이구나")
# 그 외는 에러 처리
else:
print("지원하지 않는 인자입니다")
# 호출 예시
greet("길동")
greet("길동", 30)
greet(name="길동", age=30)
greet(age=30) # 지원하지 않는 인자입니다
다른 구현 형식으로는 데코레이터가 있다고 하지만 아직 공부하기 전이니 추후에 기억해서 만들어보자.
'Developer > Python' 카테고리의 다른 글
python : 할당과 복사 (0) | 2025.03.26 |
---|---|
python : Iterator, Generator (0) | 2025.03.26 |
python : 자료형 . 기본 자료형 및 내장 자료형 (0) | 2025.03.20 |
python : 변수 (0) | 2025.03.19 |