#!/usr/bin/env python # coding: utf-8 # *** # *** # # 21. 상속과 다형성 # *** # *** # *** # ## 1 클래스 상속 # *** # ### 1-1 클래스 상속과 이름 공간의 관계 # - 상속의 이유 # - 코드의 재사용 # - 상속받은 자식 클래스는 상속을 해준 부모 클래스의 모든 기능을 그대로 사용 # - 자식 클래스는 필요한 기능만을 정의하거나 기존의 기능을 변경할 수 있음 # In[1]: class Person: def __init__(self, name, phone=None): self.name = name self.phone = phone def __str__(self): return '' % (self.name, self.phone) # In[2]: class Employee(Person): # 괄호 안에 쓰여진 클래스는 슈퍼클래스를 의미한다. def __init__(self, name, phone, position, salary): Person.__init__(self, name, phone) # Person클래스의 생성자 호출 self.position = position self.salary = salary # - 이름 공간의 포함관계 # - 자식 클래스 > 부모 클래스 # ![inheritance](images/inheritance2.png) # In[3]: 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 # ![inheritance](images/inheritance3.png) # ### 1-2 생성자 호출 # - 서브 클래스의 생성자는 슈퍼 클래스의 생성자를 자동으로 호출하지 않는다. # In[4]: class Super: def __init__(self): print 'Super init called' class Sub(Super): def __init__(self): print 'Sub init called' s = Sub() # - 서브 클래스의 생성자에서 슈퍼 클래스의 생성자를 명시적으로 호출해야 한다. # In[3]: class Super: def __init__(self): print 'Super init called' class Sub(Super): def __init__(self): Super.__init__(self) # 명시적으로 슈퍼클래스의 생성자를 호출한다. print 'Sub init called' s = Sub() # - 서브 클래스에 생성자가 정의되어 있지 않은 경우에는 슈퍼 클래스의 생성자가 호출된다. # In[66]: class Super: def __init__(self): print 'Super init called' class Sub(Super): pass s = Sub() # ### 1-3 메쏘드의 대치 (메소드 오버라이드 - Override) # - 서브 클래스에서 슈퍼 클래스에 정의된 메소드를 재정의하여 대치하는 기능 # In[1]: class Person: def __init__(self, name, phone=None): self.name = name self.phone = phone def __str__(self): return '' % (self.name, self.phone) class Employee(Person): def __init__(self, name, phone, position, salary): Person.__init__(self, name, phone) self.position = position self.salary = salary p1 = Person('gslee', 5284) m1 = Employee('kslee', 5224, 'President', 500) print p1 print m1 # In[2]: class Employee(Person): def __init__(self, name, phone, position, salary): Person.__init__(self, name, phone) self.position = position self.salary = salary def __str__(self): return '' % (self.name, self.phone, self.position, self.salary) p1 = Person('gslee', 5284) m1 = Employee('kslee', 5224, 'President', 500) print p1 print m1 # ### 1-4 다형성(Polymorphism) # - 상속 관계 내의 다른 클래스들의 인스턴스들이 같은 멤버 함수 호출에 대해 각각 다르게 반응하도록 하는 기능 # - 연산자 오버로딩도 다형성을 지원하는 중요한 기술 # - 예를 들어, a와 b의 객체 형에 따라 a + b의 + 연산자 행동 방식이 변경되는 것 # # - 다형성의 장점 # - 적은 코딩으로 다양한 객체들에게 유사한 작업을 수행시킬 수 있음 # - 프로그램 작성 코드 량이 줄어든다. # - 코드의 가독성을 높혀준다. # # - 파이썬에서 다형성의 장점 # - 형 선언이 없다는 점에서 파이썬에서는 다형성을 적용하기가 더욱 용이하다. # - 실시간으로 객체의 형이 결정되므로 단 하나의 메소드에 의해 처리될 수 있는 객체의 종류에 제한이 없다. # - 즉, 다른 언어보다 코드의 양이 더욱 줄어든다. # In[57]: 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() # *** # ## 2 내장 자료형과 클래스의 통일 # *** # - 내장 자료형(list, dict, tuple, string)을 상속하여 사용자 클래스를 정의하는 것 # - 내장 자료형과 사용자 자료형의 차이를 없에고 통일된 관점으로 모든 객체를 다룰 수 있는 방안 # - 클래스 정의는 새로운 자료형의 정의임 # ### 2-1 리스트 서브 클래스 만들기 # In[11]: a = list() print a print dir(a) # - 아래 예제는 내장 자료형인 list를 상속하여 뺄셈 연산(-)을 추가함 # In[51]: 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) Stack 클래스 정의 예 # - 슈퍼 클래스로 list 클래스를 지닌다. # - 즉, list 클래스를 확장하여 Stack 클래스를 정의함 # In[12]: 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 # #### 2) Queue 클래스 정의 예 # - 슈퍼 클래스로 역시 list를 지닌다. # - 즉, list 클래스를 확장하여 Queue 클래스를 정의함 # In[13]: 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() # ### 2-2 사전 서브 클래스 만들기 # In[6]: a = dict() print a print dir(a) # - 아래 예제는 keys() 메소드를 정렬된 키값 리스트를 반환하도록 재정의한다. # In[56]: class MyDict(dict): def keys(self): K = dict.keys(self) # 언바운드 메소드 호출 --> K = self.keys() 라고 호출하면 무한 재귀 호출 K.sort() return K d = MyDict({'one':1, 'two':2, 'three':3}) print d.keys() print d2 = {'one':1, 'two':2, 'three':3} print d2.keys() # *** # ## 3 상속 관계에 있는 클래스들의 정보 획득 # *** # ### 3-1 객체가 어떤 클래스에 속해 있는지 확인하기 # - 객체의 자료형 비교 방법 I (전통적 방법) # In[5]: import types print type(123) == types.IntType print type(123) == type(0) # - 객체의 자료형 비교 방법 II (새로운 방법) # - isinstance() 내장 함수와 기본 객체 클래스 사용 # In[10]: print isinstance(123, int) print int # - 서브 클래스의 인스턴스는 슈퍼 클래스의 인스턴스이기도 하다. # In[18]: class A: pass class B: def f(self): pass class C(B): pass def check(obj): print obj, '=>', if isinstance(obj, A): print 'A', if isinstance(obj, B): print 'B', if isinstance(obj, C): print 'C', print a = A() b = B() c = C() check(a) check(b) check(c) # ### 3-2 클래스 간의 상속 관계 알아내기 # - issubclass() 내장 함수 활용 # In[20]: class A: pass class B: def f(self): pass class C(B): pass def check(obj): print obj, '=>', if issubclass(obj, A): print 'A', if issubclass(obj, B): print 'B', if issubclass(obj, C): print 'C', print check(A) check(B) check(C) #

참고 문헌: 파이썬(열혈강의)(개정판 VER.2), 이강성, FreeLec, 2005년 8월 29일