상속의 이유
부모 클래스 메소드 호출 방법
super()
super(Subclass, self)
super(Subclass, self)
call is equivalent to the parameterless super()
call.class Person:
def __init__(self, name, phone=None):
self.name = name
self.phone = phone
def __str__(self):
return '<Person {0} {1}>'.format(self.name, self.phone)
class Employee(Person): # 괄호 안에 쓰여진 클래스는 슈퍼클래스를 의미한다.
def __init__(self, name, phone, position, salary):
#Person.__init__(self, name, phone) # Person클래스의 생성자 호출 --> Unbound Method Call
#super().__init__(name, phone) # --> Bound Method Call - 1
super(Employee, self).__init__(name, phone) # --> Bound Method Call - 2
self.position = position
self.salary = salary
p1 = Person('홍길동', 1498)
print(p1.name)
print(p1)
print()
m1 = Employee('손창희', 5564, '대리', 200)
m2 = Employee('김기동', 8546, '과장', 300)
print(m1.name, m1.position) # 슈퍼클래스와 서브클래스의 멤버를 하나씩 출력한다.
print(m1)
print(m2.name, m2.position)
print(m2)
홍길동 <Person 홍길동 1498> 손창희 대리 <Person 손창희 5564> 김기동 과장 <Person 김기동 8546>
l1 = [x for x in dir(p1) if not x.startswith("__")]
print(l1)
['name', 'phone']
l2 = [x for x in dir(m1) if not x.startswith("__")]
print(l2)
['name', 'phone', 'position', 'salary']
class Super:
def __init__(self):
print('Super init called')
class Sub(Super):
def __init__(self):
print('Sub init called')
s = Sub()
Sub init called
class Super:
def __init__(self):
print('Super init called')
class Sub(Super):
def __init__(self):
#Super.__init__(self) # Unbound 방식으로 슈퍼클래스의 생성자를 호출한다.
#super().__init__() # 또는 왼쪽처럼 Bound 메소드 호출
super(Sub, self).__init__() # 또는 왼쪽처럼 Bound 메소드 호출
print('Sub init called')
s = Sub()
Super init called Sub init called
class Super:
def __init__(self):
print('Super init called')
class Sub(Super):
pass
s = Sub()
Super init called
class Person:
def __init__(self, name, phone=None):
self.name = name
self.phone = phone
def __str__(self):
return '<Person %s %s>' % (self.name, self.phone)
class Employee(Person):
def __init__(self, name, phone, position, salary):
#Person.__init__(self, name, phone)
super(Employee, self).__init__(name, phone)
self.position = position
self.salary = salary
p1 = Person('gslee', 5284)
m1 = Employee('kslee', 5224, 'President', 500)
print(p1)
print(m1)
<Person gslee 5284> <Person kslee 5224>
class Employee(Person):
def __init__(self, name, phone, position, salary):
#Person.__init__(self, name, phone)
super(Employee, self).__init__(name, phone)
self.position = position
self.salary = salary
def __str__(self):
return '<Employee %s %s %s %s>' % (self.name, self.phone, self.position, self.salary)
p1 = Person('gslee', 5284)
m1 = Employee('kslee', 5224, 'President', 500)
print(p1)
print(m1)
<Person gslee 5284> <Employee kslee 5224 President 500>
class Employee(Person):
def __init__(self, name, phone, position, salary):
#Person.__init__(self, name, phone)
super(Employee, self).__init__(name, phone)
self.position = position
self.salary = salary
def __str__(self):
s = super().__str__() # 부모 객체의 메소드 호출 (bound)
s = s.replace("Person", "Employee")
return s + ' - <%s %s>' % (self.position, self.salary)
p1 = Person('gslee', 5284)
m1 = Employee('kslee', 5224, 'President', 500)
print(p1)
print(m1)
<Person gslee 5284> <Employee kslee 5224> - <President 500>
class Employee(Person):
def __init__(self, name, phone, position, salary):
#Person.__init__(self, name, phone)
super(Employee, self).__init__(name, phone)
self.position = position
self.salary = salary
def __str__(self):
s = Person.__str__(self) # 부모 객체의 메소드 호출 (unbound)
s = s.replace("Person", "Employee")
return s + ' - <%s %s>' % (self.position, self.salary)
p1 = Person('gslee', 5284)
m1 = Employee('kslee', 5224, 'President', 500)
print(p1)
print(m1)
<Person gslee 5284> <Employee kslee 5224> - <President 500>
상속 관계 내의 다른 클래스들의 인스턴스들이 같은 멤버 함수 호출에 대해 각각 다르게 반응하도록 하는 기능
다형성의 장점
파이썬에서 다형성의 장점
class Animal:
def cry(self):
print('...')
class Dog(Animal):
def cry(self):
print('멍멍')
class Duck(Animal):
def cry(self):
print('꽥꽥')
class Fish(Animal):
pass
for each in (Dog(), Duck(), Fish()):
each.cry()
멍멍 꽥꽥 ...
a = list()
print(a)
print(dir(a))
[] ['__add__', '__class__', '__contains__', '__delattr__', '__delitem__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__gt__', '__hash__', '__iadd__', '__imul__', '__init__', '__init_subclass__', '__iter__', '__le__', '__len__', '__lt__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__reversed__', '__rmul__', '__setattr__', '__setitem__', '__sizeof__', '__str__', '__subclasshook__', 'append', 'clear', 'copy', 'count', 'extend', 'index', 'insert', 'pop', 'remove', 'reverse', 'sort']
class MyList(list):
def __sub__(self, other): # '-' 연산자 중복 함수 정의
for x in other:
if x in self:
self.remove(x) # 각 항목을 하나씩 삭제한다.
return self
L = MyList([1, 2, 3, 'spam', 4, 5])
print(L)
print()
L = L - ['spam', 4]
print(L)
[1, 2, 3, 'spam', 4, 5] [1, 2, 3, 5]
class Stack(list): # 클래스 정의
push = list.append
s = Stack() # 인스턴스 생성
s.push(4)
s.push(5)
print(s)
print()
s = Stack([1,2,3])
s.push(4)
s.push(5)
print(s)
print()
print(s.pop()) # 슈퍼 클래스인 리스트 클래스의 pop() 메소드 호출
print(s.pop())
print(s)
[4, 5] [1, 2, 3, 4, 5] 5 4 [1, 2, 3]
class Stack(list): # 클래스 정의
def push(self, other):
self.append(other)
s = Stack() # 인스턴스 생성
s.push(4)
s.push(5)
print(s)
print()
s = Stack([1,2,3])
s.push(4)
s.push(5)
print(s)
print()
print(s.pop()) # 슈퍼 클래스인 리스트 클래스의 pop() 메소드 호출
print(s.pop())
print(s)
[4, 5] [1, 2, 3, 4, 5] 5 4 [1, 2, 3]
class Queue(list):
enqueue = list.append
def dequeue(self):
return self.pop(0)
q = Queue()
q.enqueue(1) # 데이터 추가
q.enqueue(2)
print(q)
print(q.dequeue()) # 데이터 꺼내기
print(q.dequeue())
[1, 2] <class 'type'> 1 <class 'type'> 2
a = dict()
print(a)
print(dir(a))
{} ['__class__', '__contains__', '__delattr__', '__delitem__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__iter__', '__le__', '__len__', '__lt__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__setitem__', '__sizeof__', '__str__', '__subclasshook__', 'clear', 'copy', 'fromkeys', 'get', 'items', 'keys', 'pop', 'popitem', 'setdefault', 'update', 'values']
class MyDict(dict):
def keys(self):
K = list(dict.keys(self)) # 언바운드 메소드 호출 --> K = list(self.keys()) 라고 호출하면 무한 재귀 호출
K.sort()
return K
d = {'b':1, 'c':2, 'a':3}
print(d.keys())
print(list(d.keys()))
print()
d2 = MyDict({'b':1, 'c':2, 'a':3})
print(d2.keys())
dict_keys(['b', 'c', 'a']) ['b', 'c', 'a'] ['a', 'b', 'c']
class MyDict(dict):
def keys(self):
K = list(super().keys()) # 바운드 메소드 호출
K.sort()
return K
d = {'b':1, 'c':2, 'a':3}
print(d.keys())
print(list(d.keys()))
print()
d2 = MyDict({'b':1, 'c':2, 'a':3})
print(d2.keys())
dict_keys(['b', 'c', 'a']) ['b', 'c', 'a'] ['a', 'b', 'c']
print(int)
<class 'int'>
print(type(123) == int)
print(type(123) == type(0))
a = 12345678
print(type(a) == type(0))
True True True
print(isinstance(123, int))
True
class A:
pass
class B:
def f(self):
pass
class C(B):
pass
def check(obj):
print(obj, '=>', end=" ")
if isinstance(obj, A):
print('A', end="")
if isinstance(obj, B):
print('B', end="")
if isinstance(obj, C):
print('C', end="")
print()
a = A()
b = B()
c = C()
check(a)
check(b)
check(c)
<__main__.A object at 0x10c2f9c50> => A <__main__.B object at 0x10c2dae48> => B <__main__.C object at 0x10c2f9ac8> => BC
class A:
pass
class B:
def f(self):
pass
class C(B):
pass
def check(obj):
print(obj, '=>', end=" ")
if issubclass(obj, A):
print('A', end="")
if issubclass(obj, B):
print('B', end="")
if issubclass(obj, C):
print('C', end="")
print()
check(A)
check(B)
check(C)
<class '__main__.A'> => A <class '__main__.B'> => B <class '__main__.C'> => BC
class X: pass
class Y: pass
class Z: pass
class A(X, Y): pass
class B(Y, Z): pass
class M(B, A, Z): pass
x = X()
y = Y()
z = Z()
a = A()
b = B()
m = M()
print(issubclass(A, X))
print(isinstance(a, X))
print()
print(issubclass(B, X))
print(isinstance(b, X))
print()
print(B.mro())
True True False False [<class '__main__.B'>, <class '__main__.Y'>, <class '__main__.Z'>, <class 'object'>]
print(issubclass(M, Z))
print(isinstance(m, Z))
print()
print(issubclass(M, X))
print(isinstance(m, X))
print()
print(issubclass(M, Y))
print(isinstance(m, Y))
True True True True True True
print(M.mro()) # method resolution order
[<class '__main__.M'>, <class '__main__.B'>, <class '__main__.A'>, <class '__main__.X'>, <class '__main__.Y'>, <class '__main__.Z'>, <class 'object'>]
class Human:
def __init__(self, name):
self.name = name
class Coder:
def __init__(self, skills):
self.skills = skills
class Pythonista(Human, Coder):
def __init__(self, name, skills, dream):
Human.__init__(self, name)
Coder.__init__(self, skills)
self.dream = dream
obj = Pythonista("Alice", 3, 10)
print(obj.name)
print(obj.skills)
print(obj.dream)
Alice 10 3
class A:
def __init__(self):
print("Class A __init__()")
class B(A):
def __init__(self):
print("Class B __init__()")
A.__init__(self)
class C(A):
def __init__(self):
print("Class C __init__()")
A.__init__(self)
class D(B, C):
def __init__(self):
print("Class D __init__()")
B.__init__(self)
C.__init__(self)
d = D()
Class D __init__() Class B __init__() Class A __init__() Class C __init__() Class A __init__()
class A:
def __init__(self):
print("Class A __init__()")
class B(A):
def __init__(self):
print("Class B __init__()")
super().__init__()
class C(A):
def __init__(self):
print("Class C __init__()")
super().__init__()
class D(B, C):
def __init__(self):
print("Class D __init__()")
super().__init__()
d = D()
print(D.mro())
Class D __init__() Class B __init__() Class C __init__() Class A __init__() [<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>]
class A:
def __init__(self):
print("Class A __init__()")
class B(A):
def __init__(self):
print("Class B __init__()")
super(B, self).__init__()
class C(A):
def __init__(self):
print("Class C __init__()")
super(C, self).__init__()
class D(B, C):
def __init__(self):
print("Class D __init__()")
super(D, self).__init__()
d = D()
print(D.mro())
Class D __init__() Class B __init__() Class C __init__() Class A __init__() [<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>]
참고 문헌: 파이썬(열혈강의)(개정판 VER.2), 이강성, FreeLec, 2005년 8월 29일