상속은 객체지향 언어에만 있는 개념이다.
상위 -> 하위 -> 자식 클래스 내에 있는 변수, 함수를 상속하여 연동해서 사용 가능하다.
상속은 클래스 간의is-a
관계이다. ex. 푸들은 강아지다. 꽃은 식물이다.처럼 상위 클래스에 해당 됨.
자식 클래스와 부모 클래스가 갖는 공통 변수와 함수는 부모 클래스에 정의를 해둔다.
- 자식 클래스 또는 서브 클래스라 칭한다.
- 부모 클래스 또는 슈퍼 클래스라 칭한다.
class 부모클래스 :
생성자
메소드
# 자식 클래스에서 부모 클래스 이름을 인수로 넣어줘 변수 및 함수들을 사용할 수 있다.
class 자식 클래스 (부모 클래스명) :
#부모 클래스의 인수 작성
def __init__(self, make, model, color, price, payload) :
#부모클래스에 대한 생성자 작성 (상속되기 때문에 다시 정의할 필요 X)
super().__init__(make, model, color, price)
#자식클래스에서 정의한 인수는 정의해줘야 함.
self.payload = payload
메소드
class 자식 클래스 (부모 클래스명) :
생성자
메소드
A. obj에 자식클래스를 정의한거라 자식클래스는 인수를 2개 받으니까 인수가 2개여도 되는거임.
#Super Class
class Car :
def __init__(self, speed) :
self.speed = speed
def setSpeed(self, speed) :
self.speed = speed
def getDesc(self) :
return '차량 = ({})'.format(self.speed)
#Sub Class
class SportsCar(Car) :
def __init__(self, speed, turbo) : #전달 받는 인수가 2개
super().__init__(speed)
self.turbo = turbo
def setTurbo(self, turbo) :
self.turbo = turbo
obj = SportsCar(100, True)
print(obj.getDesc())
obj.setTurbo(False)
#Inheritance
class Human :
def __init__(self, age, name) :
self.age = age
self.name = name
def intro(self) :
print('{}살, {}입니다.'.format(self.age, self.name))
class Student(Human) :
def __init__(self, age, name, st_code) :
super().__init__(age, name)
self.st_code = st_code
#부모클래스에서 상속 받음
def intro(self) :
super().intro() #상속 받기 위한 코드
print('학번 : {}'.format(self.st_code)) #부모 클래스에서 상속받은 코드에 추가한 코드
def study(self) :
print('하늘 천, 땅 지, 검을 현, 누를 황')
#내가 생각한 코드는 학번도 study에 들어가야한다 싶어 함께 묶음.
#def study(self) :
#print('학번 : {}'.format(self.st_code))
#print('하늘 천, 땅 지, 검을 현, 누를 황')
kim = Human(29, '김상현')
kim.intro()
lee = Student(40, '이지수', 930011)
lee.intro()
lee.study()
set 설정자 메소드
get 접근자 메소드
A. 클래스에 인수가 들어가는 경우는 자식 클래스가 부모 클래스를 상속받을 때 사용한다.
아래 코드는?
class MyCounter(object) :
#생성자 메소드를 정의.
def __init__(self, low, high) :
self.current = low
self.high = high
#이터레이터 객체로서 자신을 반환.
def __iter__(self) :
return self
def __next__(self) :
#current가 high 보다 크면 StopIteration 예외 발생.
#current가 high 보다 작으면 다음 값을 반환.
if self.current > self.high :
raise StopIteration
else :
self.current += 1
return self.current -1
c = MyCounter(1, 10)
for i in c :
print(i, end=' ')
print()
list = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
for i in list :
print(i, end=' ')
클래스를 호출할 인수를 작성하는데 그 인수는 생성자를 통해 초기화가 되어 정의되고 정의된 값을 클래스 내 함수에서 변수로 사용된다.
덮어쓴다. 부모클래스에서 정의한 함수를 자식클래스에서 재정의할 경우 자식 클래스의 함수가 우선 시 된다.
#Overriding
class Animal :
def __init__(self, name=' ') :
self.name = name
def eat(self):
print('동물이 먹고 있습니다.')
class Dog(Animal) :
def __init__(self) :
super().__init__()
def eat(self) :
print('강아지가 먹고 있습니다.')
d = Dog()
d.eat()
=============================== RESTART: C:\Users\GIEC\Desktop\기초문법\1103\test.py ==============================
강아지가 먹고 있습니다.
#자식 클래스에서 eat 메소드를 재정의 했으므로 '강아지가 먹고 있습니다.'가 출력된다.
원의 면적과 둘레를 구해야 하는데 원 클래스의 내용과 사각형 클래스의 내용은 같다. 하지만 둘 다 다른 클래스로 부모 클래스만 공유한다. 따라서 원의 클래스와 사각형의 클래스는 똑같은 이름의 함수를 사용해도 내용을 달리하여 다른 결과를 도출해낼 수 있다.
import math
class Shape :
def __init__(self, x, y) :
self.x = x
self.y = y
def area(self) :
print('계산할 수 없음!')
def perimeter(self) :
print('계산할 수 없음!')
class Rectangle(Shape) :
def __init__(self, x, y, w, h) :
super().__init__(x, y)
self.w = w
self.h = h
def area(self) :
return self.w * self.h
def perimeter(self) :
return 2 * (self.w + self.h)
#부모클래스에서 필요없는 값은 받을 필요가 없다.
class Circle(Shape) : #부모클래스를 상속 하지만
def __init__(self, r) : #내가 정의할 값만 가져옴.
self.r = r
def area(self) :
return math.pi * self.r**2
def perimeter(self) :
return 2 * math.pi * self.r
r = Rectangle(0, 0, 100, 200)
c = Circle(10)
print('사각형의 면적', r.area())
print('사각형의 둘레', r.perimeter())
print('원의 면적', c.area())
print('원의 둘레', c.perimeter())
class Person :
def __init__(self, name, number) :
self.name = name
self.number = number
class Student(Person) :
UNDERGRADUATE = 0
POSTGRADUATE = 1
def __init__(self, name, number, studentType ) :
super().__init__(name, number)
self.studentType = studentType
self.gpa = 0
self.classes =[ ]
def enrollCourse(self, course) :
self.classes.append(course)
def __str__(self) :
return '''이름 = {}
주민번호 = {}
학생타입 = {}
수강과목 = {}
평점 = {}'''.format(self.name, self.number, self.studentType, self.classes, self.gpa)
class Teacher(Person) :
def __init__(self, name, number ) :
super().__init__(name, number)
self.classes =[ ]
self.pay = 3000000
def assignTeaching(self, course) :
self.classes.append(course)
def __str__(self) :
return '''이름 = {}
주민번호 = {}
강의과목 = {}
월급 = {}'''.format(self.name, self.number, self.classes, self.pay)
hong = Student('홍길동', '12345678', Student.UNDERGRADUATE)
hong.enrollCourse('자료구조')
print(hong)
print('=' * 20)
kim = Teacher('김철수', '87654321')
kim.assignTeaching('Python')
print(kim)
#종합 예제 2
class BankAccount :
def __init__(self, name, number, balance) :
self.name = name
self.number = number
self.balance = balance
def withdraw(self, amount) :
self.balance -= amount
return self.balance
def deposit(self, amount) :
self.balance += amount
return self.balance
class SavingsAccount(BankAccount) :
def __init__(self, name, number, balance, interest_rate) :
super().__init__(name, number, balance)
self.interest_rate = interest_rate
def set_interest_rate(self, interest_rate) :
self.interest_rate = interest_rate
def get_interest_rate(self) :
return self.interest_rate
def add_interest(self) : #예금에 이자를 더 함.
self.balance += self.balance * self.interest_rate
class CheckAccount(BankAccount) :
def __init__(self, name, number, balance) :
super().__init__(name, number, balance)
self.withdraw_charge = 10000 #수표 수수료 발행.
def withdraw(self, amount) :
return BankAccount.withdraw(self, amount + self.withdraw_charge)
a1 = SavingsAccount('홍길동', 123456, 10000, 0.05)
a1.add_interest()
a1.deposit(1000) #SavingsAccount에서 deposit 함수를 정의하지 않았지만 사용 가능.
print('저축 예금의 잔액 =', a1.balance)
print('=' * 20)
a2 = CheckAccount('김철수', 1234567, 2000000)
a2.withdraw(100000)
print('저축 예금의 잔액 =', a2.balance)
자식클래스에서 부모클래스의 함수를 사용하려면 super().메소드() 형식으로 불러와야 한다.
class Employee :
def __init__(self, name, salary) :
self.name = name
self.salary = salary
def getSalary(self) :
return salary
class Manager(Employee) :
def __init__(self, name, salary, bonus) :
super().__init__(name, salary)
self.bonus = bonus
def getSalary(self) :
salary = super().getSalary()
return salary + self.bonus
def __str__(self) :
return '이름 : {}, 월급 : {}, 보너스 : {}'.format(self.name, self.salary, self.bonus)
kim = Manager('김철수', 2000000, 1000000)
print(kim)
A. 클래스 외부에서 변수에 클래스를 정의하면 클래스가 정의된 변수를 인스턴스라 함.
https://blog.naver.com/codeitofficial/221684462326
동일한 코드로 다양한 객체를 처리할 수 있는 기법.
리스트를 만들어 for문에 사용할 수 있다.
class Animal :
def __init__(self, name) :
self.name = name
def speak(self) :
return '알수 없음.'
class Dog(Animal) :
#def __init__(self, name) : #부모 클래스와 인수가 동일하면 생략 가능
#super().__init__(name) #생략 가능.
def speak(self) :
return '멍멍!'
class Cat(Animal) :
#def __init__(self, name) :
#super().__init__(name)
def speak(self) :
return '야옹!'
animalList = [Dog('dog1'), Dog('dog2'), Cat('cat1')]
for a in animalList :
print(a.name + ' : ' + a.speak())
자식 클래스에서 함수를 재정의 하지 않았을 경우 부모 클래스에서 처리할 코드가 아니라서 개발자가 알 수 있도록 일부러 에러를 발생 시키고 자식 클래스에서 코드를 재정의 하도록 유도한다.
init도 작성할 필요가 없으면 pass를 작성해도 된다.
class Vehicle :
def __init__(self, name) :
self.name = name
def drive(self) :
raise NotImplementedError('이것은 추상 메소드입니다.') #자식 클래스에서 함수를 재정의 하지 않았을 경우 에러를 낸다.
def stop(self) :
raise NotImplementedError('이것은 추상 메소드입니다.')
class Car(Vehicle) :
def drive(self) :
return '승용차를 운전합니다.'
def stop(self) :
return '승용차를 정지합니다.'
class Truck(Vehicle) :
def drive(self) :
return '트럭을 운전합니다.'
def stop(self) :
return '트럭을 정지합니다.'
cars = [Truck('truck1'), Truck('truck2'), Car('car1')]
for car in cars :
print(car.name + ' : ' + car.drive())
repr
init
is-a
has-a