Python
[Python] Part.6 상속과 예외처리
c1oud9
2023. 2. 15. 01:13
ch06-01. 상속
클래스의 계층구조

상속이란?
클래스의 상속이란 한 클래스가 다른 클래스로부터 데이터 속성과 메서드를 물려받는 것.
상속하는 클래스를 기반(base) 클래스 또는 상위(super) 클래스라고 하고 상속 받는 클래스를 파생(derived) 또는 하위(sub) 클래스라고 한다.
파이썬에서 상속 하는 법
class A:
def 함수1 (self, 변수1 , 변수2 , ...):
return 결과
class B(A):\
def 함수2 (self, 변수1 , 변수2 , ...):
return 결과
=> B 는 아래와 같음 .
class B:
def 함수1 (self, 변수1 , 변수2 , ...):
return 결과
def 함수2 (self, 변수1 , 변수2 , ...):
return 결과
예시
class add_calculator :
def addition (self, x , y):
return x + y
class good_calculator (add_calculator):
def substraction (self, x , y):
return x - y
_
calc1=add_calculator()
_
calc1.addition(3, 4)
# result
7
_
calc2 = good_calculator()
_
calc2.addition(3, 4)
# result
7
_
calc2.substraction(4, 3)
# result
1
부모의 기능을 불러오려면
super() 이용하면 부모에게 정의된 함수를 불러올 수 있다.
class add_calculator:
def addition(self, x, y):
return x+y
class good_calculator(add_calculator):
def addition(self, x, y):
print(super().addition(x,y)) # 부모의 addition 메소드를 불러와서 print(x+y)가 될 것이다.
print('또?')
print(super().addition(x,y))
_
calc2.addition(3, 4)
# result
7
또?
7
overriding
만약에, 부모의 메소드와 이름이 똑같은 메소드를 자식에게 정의하면?
class A:
def method(self, 변수):
결과
class B(A):
def method(self, 변수):
다른 결과
A의 메소드는 무시되고 B는 새롭게 정의된 메소드를 사용!
다중 상속

class A:
def 함수(self):
결과
class B:
def 함수(self):
결과
class C(A,B):
pass
위와같은 상황에서 C는 A, B중에 어떤 함수를 상속받을까?
=> 먼저 입력한 A의 함수를 상속받는다.
ch06-02. 추상 클래스와 isinstance
추상 클래스
- 추상 클래스는 abc 모듈의 ABCMeta 클래스를 상속받아 만든다.
- 추상 클래스는 자신의 객체를 생성할 수 없다.
- 추상 메소드라는 @abstractmethod 데코레이터를 사용하여 자신의 하위객체에게 특정 메소드의 생성을 강제할 수 있다.
- 추상 메소드는 이름만 존재하고 내용은 없다.
- 추상 클래스는 abc 모듈의 ABCMeta 클래스를 상속받아 만든다. 이때 반드시 metaclass=메타클래스이름 의 형태로 상속받는다.
- 추상 클래스는 자신의 객체를 생성할 수 없다.
- 추상 메소드라는 @abstractmethod 데코레이터를 사용하여 자신의 하위객체에게 특정 메소드의 생성을 강제할 수 있다.
- 추상 메소드는 이름만 존재하고 내용은 없다
from abc import *
class Abstract(metaclass = ABCMeta):
@abstractmethod
def method(self):
pass
class test(Abstract): # 이 경우 abstract method인 method를 정의하지 않아서 오류발생
pass
_
test1 = test()
# result
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-21-b98d2860ac1d> in <module>
----> 1 test1 = test()
TypeError: Can't instantiate abstract class test with abstract methods method
from abc import *
class Abstract(metaclass = ABCMeta):
@abstractmethod
def method(self):
pass
class test(Abstract): # abstract method인 method를 정의 오류발생 안함
def method(self):
pass
_
test1 = test()
# result
error 없음
isinstance
isinstance(변수, 클래스이름)은 주어진 변수의 값이 클래스의 인스턴스인지 여부를 반환해 주는 함수!
a = 3
_
isinstance(a, int)
# result
True
_
isinstance(test1, test)
# result
True
_
isinstance(test1, int)
# result
False
ch06-03. 예외 처리
Try ~ except
try:
에러 문장
except:
에러 났을 때 실행할 문장
위와 같이 입력할 경우 에러 문장에서 에러가 발생했을 때 except에 있는 문장이 실행된다.
try:
에러 문장
except Exception as e: # 이렇게 as e라고 적어 놓으면 발생할 에러문이 string의 형태로 e에 저장!
print(e)
에러 났을 때 실행할 문장
위와 같이 입력할 경우 에러 문장에서 에러가 발생했을 때 except에 있는 문장이 실행된다.
try:
에러 문장
except:
에러 났을 때 실행할 문장
else:
에러가 안 나면 실행할 문장
finally:
에러 발생 여부와 상관없이 실행될 문장
예외의 강제 발생
raise Exception(“강제로 에러를 발생시킴“)
과 같은 방식으로 raise문을 통해 우측의 string을 출력하며 에러가 발생하게 할 수 있습니다.
예시
try:
1/0
except:
print('에러')
# result
에러
try:
1/0
except Exception as e:
print(e)
print('에러')
# result
division by zero
에러
raise Exception('내가 만든 에러')
#result
---------------------------------------------------------------------------
Exception Traceback (most recent call last)
<ipython-input-31-04b2f0b9af1e> in <module>
----> 1 raise Exception('내가 만든 에러')
Exception: 내가 만든 에러
a = 3
assert a>=10, '값이 너무 작습니다.'
# result
---------------------------------------------------------------------------
AssertionError Traceback (most recent call last)
<ipython-input-32-0cce7c5f52e1> in <module>
1 a = 3
----> 2 assert a>=10, '값이 너무 작습니다.'
AssertionError: 값이 너무 작습니다.
_
a = 13
assert a>=10, '값이 너무 작습니다.'
#result
error 없음
ch06-04. 실전 문제풀이
# 추상클래스는 ABCMeta를 상속 받고 추상메소드가 있어야함
from abc import ABCMeta, abstractmethod
class Abstract1 (metaclass=ABCMeta):
attr = '추상클래스'
@abstractmethod
def m1(self):
pass
def m2(self):
print('대박')
# 추상클래스는 객체를 못 만듬 -> error 나게 된다.
a1 = Abstract1()
# result
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-1-da8e9c6b50f5> in <module>
9 print('대박')
10 # 추상클래스는 객체를 못 만듬
---> 11 a1 = Abstract1()
TypeError: Can't instantiate abstract class Abstract1 with abstract methods m1
from abc import *
class A (metaclass = ABCMeta):
def prn(self):
print('대박')
@abstractmethod
def p2(self):
pass
# 추상클래스를 상속 받은 클래스는 반드시 추상메소드를 재정의
class A1(A):
def aa(self):
print('사건')
def p2(self):
print('아 이건 필수네')
a1 = A1()
a1.aa()
a1.p2()
a1.prn()
# result
사건
아 이건 필수네
대박
# 추상클래스
from abc import *
class Animal(metaclass = ABCMeta):
def __init__(self,eat1='그냥'):
self.eat1 = eat1
def eat(self): print('먹어야 산다')
# 추상메서드 상속받은 자식이 재정의 해야 한다
@abstractmethod
def move(self): pass
class Bird(Animal):
def move(self):
print('하늘을 난다 {}'.format(self.eat1))
class Person(Animal):
def move(self): print('두발로 걷는다 {}'.format(self.eat1))
class Fish(Animal):
def move(self): print('지느러미로 헤엄친다')
b1 = Bird(); p1 = Person('대박'); f1 = Fish()
animal = [b1, p1, f1]
for an in animal:
print('====================')
an.eat(); an.move()
# result
====================
먹어야 산다
하늘을 난다 그냥
====================
먹어야 산다
두발로 걷는다 대박
====================
먹어야 산다
지느러미로 헤엄친다
# 클래스 상속
class A:
def m1(self):
print('점심시간')
class B(A):
def m2(self):
print('1차 프로젝트 종료일')
class C(B):
def m3(self):
print('뭘 그래')
c1 = C()
c1.m1(); c1.m2(); c1.m3()
# result
점심시간
1차 프로젝트 종료일
뭘 그래
# 클래스 상속
class A:
def m1(self):
print('점심시간')
class B(A):
def m2(self):
print('1차 프로젝트 종료일')
class C(B):
def m3(self):
super().m2()
print('뭘 그래')
c1 = C()
c1.m1(); c1.m2(); c1.m3()
# result
점심시간
1차 프로젝트 종료일
1차 프로젝트 종료일
뭘 그래
class Call:
# __call__ : 객체를 메서드처럼 호출할 때 실행
def __call__(self, *a):
print('대박이야 :')
for i in a:
print(i)
c1 = Call()
c1()
c1('뭐지', '허걱', '허각', '허공')
# result
대박이야 :
대박이야 :
뭐지
허걱
허각
허공
while True:
try:
li = [1, 2, 3]
print('인덱스 번호를 입력하세요')
num1 = input()
if num1 == 'x': break
num = int(num1)
print('{} / 2 = {}'.format(li[num], li[num]/2))
except Exception as err:
print('에러다 {}'.format(err))
else: #에러가 발생하지 않았을 때 할 실행문
print('잘했어 친구')
finally: # 에러 발생여부와 관계 없이 항상 실행
print('난 무조건이야!!')
# result
인덱스 번호를 입력하세요
2
3 / 2 = 1.5
잘했어 친구
난 무조건이야!!
인덱스 번호를 입력하세요
3
에러다 list index out of range
난 무조건이야!!
인덱스 번호를 입력하세요
x
난 무조건이야!!
try: # 0 1 2 index3번째 데이터 없기 때문에
# [1, 2, 3][3]
# 'a'+1
a=[1, 2, 3]
a[4]
except TypeError: print('1번 에러')
except ZeroDivisionError: print('2번 에러')
except IndexError: print('3번 에러')
# result
3번 에러
try: # 0 1 2 index3번째 데이터 없기 때문에
# [1, 2, 3][3]
# 'a'+1
4 / 0
except TypeError: print('1번 에러')
except ZeroDivisionError: print('2번 에러')
except IndexError: print('3번 에러')
# result
2번 에러
try: # 0 1 2 index3번째 데이터 없기 때문에
# [1, 2, 3][3]
# 'a'+1
'a'+1
except TypeError: print('1번 에러')
except ZeroDivisionError: print('2번 에러')
except IndexError: print('3번 에러')
# result
1번 에러
# Generator Expression
# 내부함수인 yieid를 수행
g1 = (n+n for n in range(21))
# print(list(g1))
for i in range(10):
val = next(g1)
print(val)
# 나머지 데이터 출력
# for i in g1:
# print(i)
# result
0
2
4
6
8
10
12
14
16
18
def yourRange(start, end):
current = start
while current < end:
yield current
current +=1
return
for i in yourRange(0, 5):
print(i)
# result
0
1
2
3
4
class Base:
def m1(self):
print('대박')
class Derived(Base): # 파이썬의 살속(?)은 ()
def m2(self):
print('사건')
if __name__=='__main__':
b1 = Base(); b1.m1(); # b1.m2() # Base에 n2라는 메소드가 없음
d1 = Derived(); d1.m1(); d1.m2()
# Derived에 없는 메소드 n1()이 실행되는 이유는 상속
# result
대박
대박
사건
# 1**3, 2**3,…, 10**3
li = [ n**n for n in range(1, 11)]
print(li)
# result
[1, 4, 27, 256, 3125, 46656, 823543, 16777216, 387420489, 10000000000]
class A:
def m1(self):
print('난 A')
class B:
def m2(self):
print('난 B')
class C:
def m3(self):
print('난 C')
class F(A, B, C):
pass
f1 = F()
f1.m1(); f1.m2(); f1.m3()
# result
난 A
난 B
난 C
class MyException(Exception): # Exception 또한 클래스
def __init__(self, arg):
super().__init__('정수가 아녀 : {}'.format(arg))
def conver(num):
if num.isdigit():
return int(num)
else:
raise MyException(num)
try:
print('숫자를 입력하세요')
num = input()
a = conver(num)
except MyException as err:
print('에러네 : {}'.format(err))
else:
print('입력한 수 {} 타입 {}'.format(a, type(a)))
# result
숫자를 입력하세요
2.5
에러네 : 정수가 아녀 : 2.5
class A1:
def m1(self):
print('난 A1야')
# overriding은 부모와 매개변수와 이름이 같은 메서드
# 재정의, 현재 객체와 가까운 메서드 사용
class A2(A1):
def m1(self):
print('난 A2야')
class A3(A2):
def m1(self):
print('난 A3야')
a1 = A1(); a2 = A2(); a3 = A3()
a1.m1(); a2.m1(); a3.m1()
# result
난 A1야
난 A2야
난 A3야
try:
print('숫자를 입력하세요')
num = int(input())
print('숫자 : ', num)
# 무조건 에러 발생, 테스트 등에서 강제 종료
raise Exception('에러야')
except Exception as err:
print('에궁 {}'.format(err))
# result
숫자를 입력하세요
2
숫자 : 2
에궁 에러야
class Base:
def __init__(self, name):
print('Base.__init__()')
self.message = '안뇽'
print(name)
# super() 무모의 생성자를 가르킴
class Derived(Base):
def __init__(self):
print('Derived __init__()')
super().__init__('승헌')
#self.message 부모의 변수를 살속 받아서 사용
print('메세지 : {}'.format(self.message))
d1 = Derived()
# result
Derived __init__()
Base.__init__()
승헌
메세지 : 안뇽
class A:
def __init__(self, name, age):
print('A__init__')
self.name = name; self.age = age
class B(A):
def __init__(self):
print('B__init__')
super().__init__('혜인', 15)
def print(self):
print('이름 : {}, 나이 : {}'.format(self.name, self.age))
b1 = B(); b1.print()
# result
B__init__
A__init__
이름 : 혜인, 나이 : 15
class add_calculator:
def addition(self, x, y):
return x+y
class good_calculator(add_calculator):
def addition(self, x, y):
print(super().addition(x, y))
print('또?')
print(super().addition(x, y))
_
calc1 = add_calculator()
_
calc1.addition(3, 4)
# result
7