이 글은 24.01.10에 본인 벨로그에 작성했던 글을 옮겨 온 것이다.
오버라이딩
- 하위 클래스에서 상위 클래스의 메서드(함수)를 재 정의(override)하는 것.
=> 상속받은 클래스의 기능을 하위 클래스에서 다시 작성한다.
=> 중복된 코드를 제거하여 객체지향 프로그래밍 시 시간 절약도 가능
추상클래스(abstract class)
- 미 구현된 메서드(=추상 메서드)을 한 개 이상 가지는 클래스를 의미한다.
- 이 추상 클래스는, 자식 클래스에서 추상 메서드를 반드시 구현하도록 강제할 수 있다.
1) 구체적으로 예를 들자면 "a라는, 선언만 되어 있고 그 외엔 구현되어있지 않은 메서드(기능)"를 갖고 있는 상위 "A"클래스를 하위 "B" 클래스가 상속받는다고 하자.
2) 이 때, "A" 클래스는 "B"클래스로 하여금 "a"기능을 반드시 구현하도록(오버라이딩 하도록) 강제할 수 있다.
3) 어떻게?? "B"클래스가 "A"클래스를 상속받았을 때 "a"기능을 구현하지 않으면 "B" 클래스로 객체 생성 시 에러가 나게 할 수 있다.
- 예시 1) 자식 클래스에서 추상 메서드를 구현하지 않은 경우.
from abc import ABCMeta
from abc import abstractmethod # 이 2가지를 import 하거나 from abc import * 해도 된다.
class plane(metaclass=ABCMeta): # 상위 클래스에 이와 같이 명시해준다.
@abstractmethod # 이 deco를 추가함으로써 flight 메서드를 추상 메서드로 정의한다.
def flight(self):
pass
def go(self):
print('go!')
def back(self):
print('back!')
class Airline(plane):
def __init__(self, c):
self.color = c
a_1 = Airline('red')
========================================
Traceback (most recent call last):
File "C:\Users\quddu\Desktop\개인 공부\제로베이스\python\class 생성\object.py", line 20, in <module>
a_1 = Airline('red')
^^^^^^^^^^^^^^
TypeError: Can't instantiate abstract class Airline with abstract method flight
이렇게, 객체 생성 시 에러가 뜬다.
에러가 난 코드와 에러 메시지를 보면, 추상 메서드를 정의하지 않아서 생긴 에러임을 알 수 있다.
- 예시 2) 자식 클래스에서 추상 메서드를 구현 한 경우.
# 자식 클래스에서 추상 메서드를 구현 한 경우.
from abc import ABCMeta
from abc import abstractmethod
class plane(metaclass=ABCMeta):
@abstractmethod
def flight(self):
pass
def go(self):
print('go!')
def back(self):
print('back!')
class Airline(plane):
def __init__(self, c):
self.color = c
def flight(self):
print('짱 빠르다')
a_1 = Airline('red')
a_1.go()
a_1.back()
a_1.flight()
============================================
go!
back!
짱 빠르다
- 그렇담, 이 추상 클래스는 어따 써먹는가?
=> 여러 하위 클래스가 하나의 상위 클래스를 상속받아 상속 클래스의 특정 기능(추상 메서드)을 각 하위 클래스의 용도에 맞게 구현해서 사용해야 하는 경우에 유용하게 쓰인다.
try~ except~ else
- 예외 처리 구문이다.
1) try : 에러가 발생할 것으로 예상되는 코드에 걸어줌
2) except : try구문에서 에러가 발생했을 때 실행시킬 코드에 걸어줌
3) else : try구문에서 에러가 발생하지 않았을 때 실행시킬 코드에 걸어줌.
- 예시. 사용자로부터 5개의 수를 입력받아 짝수, 홀수, 실수로 구분해 각각을 리스트에 저장하는 프로그램 작성
even_list=[]
odd_list=[]
float_list=[]
n = 1
while n<6: # 5개를 입력받아야 하니까.
try: # 입력된 것이 숫자인지 아닌지 걸러냄
num = float(input('숫자를 입력하세요 : '))
except: # 숫자 외 다른 것이 입력되었을 때 아래 코드 실행.
print('입력된 것은 숫자가 아닙니다. 다시 입력하세요.')
continue
else: # 입력된 것이 숫자라면, 짝수 홀수 실수를 걸러냄.
if num != round(num): # 실수 필터링
print('실수입니다')
float_list.append(num)
else: # 짝, 홀수 필터링
if num % 2 == 0:
print('짝수입니다')
even_list.append(int(num))
else:
print('홀수입니다')
odd_list.append(int(num))
n += 1
print(f'짝수 : {even_list}')
print(f'홀수 : {odd_list}')
print(f'실수 : {float_list}')
=========================================================
숫자를 입력하세요 : 1
홀수입니다
숫자를 입력하세요 : 2
짝수입니다
숫자를 입력하세요 : 3.14
실수입니다
숫자를 입력하세요 : 5
홀수입니다
숫자를 입력하세요 : ㅋㅋㅋ
입력된 것은 숫자가 아닙니다. 다시 입력하세요.
숫자를 입력하세요 : 6
짝수입니다
짝수 : [2, 6]
홀수 : [1, 5]
실수 : [3.14]
finally
- 예외 발생 여부와 관계 없이 항상 실행한다.
=> 아래와 같은 경우에 사용한다
=> 외부 자원을 사용하는 경우, 작업 도중 예외가 있었던 없었던 작업이 끝나면 외부 자원 사용도 끝내야 할 것이다. 이러한 경우에 주로 사용한다.
even_list=[]
odd_list=[]
float_list=[]
n = 1
while n<6: # 5개를 입력받아야 하니까.
try: # 입력된 것이 숫자인지 아닌지 걸러냄
num = input('숫자를 입력하세요 : ')
num = float(num)
except:
print('입력된 것은 숫자가 아닙니다. 다시 입력하세요.')
continue
else: # 숫자라면, 짝수 홀수 실수를 걸러냄.
if num != round(num): # 실수 필터링
print('실수입니다')
float_list.append(num)
else: # 짝, 홀수 필터링
if num % 2 == 0:
print('짝수입니다')
even_list.append(int(num))
else:
print('홀수입니다')
odd_list.append(int(num))
finally:
print(f'입력된 데이터는 {num}입니다')
n += 1
print(f'짝수 : {even_list}')
print(f'홀수 : {odd_list}')
print(f'실수 : {float_list}')
==========================================================
숫자를 입력하세요 : 1
홀수입니다
입력된 데이터는 1.0입니다
숫자를 입력하세요 : 2
짝수입니다
입력된 데이터는 2.0입니다
숫자를 입력하세요 : 3.14
실수입니다
입력된 데이터는 3.14입니다
숫자를 입력하세요 : ㅋㅋㅋ
입력된 것은 숫자가 아닙니다. 다시 입력하세요.
입력된 데이터는 ㅋㅋㅋ입니다
숫자를 입력하세요 : 4
짝수입니다
입력된 데이터는 4.0입니다
숫자를 입력하세요 : 5
홀수입니다
입력된 데이터는 5.0입니다
짝수 : [2, 4]
홀수 : [1, 5]
실수 : [3.14]
사용자 exception class
- 직접 예외 클래스를 만들어 사용해보자
- 예시 1)
class NoUseZero(Exception): # NoUseZero라는 예외 클래스 생성
def __init__(self, n):
super().__init__(f'{n}으로는 나눌 수 없습니다.')
def div(n1,n2):
if n2 == 0: # n2가 0인 경우 NoUseZero 예외 클래스 raise
raise NoUseZero(n2)
else: # 그 외의 경우는 나눗셈 수행
print(f'{n1}/{n2} = {n1/n2}')
num1 = int(input('숫자 1 입력 : '))
num2 = int(input('숫자 2 입력 : '))
try: # div()에서 에러가 발생할 것 같음...
div(num1, num2)
except NoUseZero as e: # 발생한다면? NoUseZero 출력.
print(e)
==================================================================
숫자 1 입력 : 5
숫자 2 입력 : 8
5/8 = 0.625
----------------------
숫자 1 입력 : 6
숫자 2 입력 : 0
0으로는 나눌 수 없습니다.
- 예시 2)
class PasswordLengthShortException(Exception):
def __init__(self, str):
super().__init__(f'{str}는 길이가 너무 짧습니다. 5자 이상 입력하세요')
class PasswordLengthLongException(Exception):
def __init__(self, str):
super().__init__(f'{str}는 길이가 너무 깁니다. 10자 이하로 입력하세요')
class PasswordWrongException(Exception):
def __init__(self, str):
super().__init__(f'{str}는 잘못된 암호입니다. 다시 입력하세요')
mypw = input('비밀번호를 입력하세요 : ')
original_pw = 'admin1234'
try:
if len(mypw) < 5: # len(mypw) < 5면 PasswordLengthShortException에러 발생시킴.
raise PasswordLengthShortException(mypw)
elif len(mypw) > 10: # len(mypw) > 10이면 PasswordLengthLongException에러 발생시킴.
raise PasswordLengthLongException(mypw)
elif mypw == original_pw: # mypw == original_pw면 accepted 출력
print('accepted')
elif mypw != original_pw: # mypw != original_pw면 PasswordWrongException에러 발생시킴.
raise PasswordWrongException(mypw)
except PasswordLengthShortException as e1:
print(e1) # PasswordLengthShortException 에러가 발생하면, 해당 메시지 출력
except PasswordLengthLongException as e2:
print(e2) # PasswordLengthLongException 에러가 발생하면, 해당 메시지 출력
except PasswordWrongException as e3:
print(e3) # PasswordWrongException 에러가 발생하면, 해당 메시지 출력
==========================================================================================
비밀번호를 입력하세요 : 1234
1234는 길이가 너무 짧습니다. 5자 이상 입력하세요
-----------------------------------------------------
비밀번호를 입력하세요 : 123456789000
123456789000는 길이가 너무 깁니다. 10자 이하로 입력하세요
-----------------------------------------------------
비밀번호를 입력하세요 : 123456
123456는 잘못된 암호입니다. 다시 입력하세요
-----------------------------------------------------
비밀번호를 입력하세요 : admin1234
accepted
텍스트 파일 열기
- 파일 모드
1) w(write): 파일을 쓸 때(덮어쓰기) 사용되고, 이 모드로 파일을 열 경우, 파일이 없으면 새로운 파일이 생성된다.
2) a(append) : 파일을 쓸 때(덧붙이기) 사용되고, 이 모드로 파일을 열 경우, 파일이 없으면 새로운 파일이 생성된다.
3) r(read) : 파일을 읽어올 때에만 사용되고, 이 모드로 파일을 열 경우, 파일이 없으면 에러가 발생한다.
4) x(exclusive creation) : 파일 생성 및 쓸 때 사용된다. w 및 a 모드와의 차이점은 파일 생성 시 동명의 파일이 있으면 에러가 발생한다는 것. 즉, 다음과 같은 상황에서 유용하다.
=> (1) 파일을 새로 만들고 싶지만, 동명의 파일이 이미 있는 경우에는 에러를 내고 싶을 때
=> (2) 동명의 파일이 이미 있는지 일일이 확인하지 않고, 안전하게 새 파일을 만들고 싶을 때
예제)
특정 정수를 입력받아 2부터 해당 정수 사이의 모든 소수를 txt파일에 입력하고, 해당 파일의 내용을 읽어들이는 프로그램 작성.
def writePrineNum(n):
file = open('C:/*****/*****/*******/prime_num.txt', 'a')
# open('파일 경로', '모드') => 파일을 해당 모드로 연다
file.write(str(n))
file.write('\n')
# 쓰기 모드로 열었으므로, write('쓸 내용')으로 텍스트를 쓴다.
file.close()
# open() 후에는 반드시 close()를 해 주어야 한다.
# 특정 정수까지의 소수를 모두 찾는 코드.
num = int(input('0보다 큰 정수 입력 : '))
for i in range(2, num+1):
flag = True
for j in range(2, i):
if i % j == 0 :
flag = False
break
if flag:
writePrineNum(i)
# 텍스트 파일에 어떤 내용이 있는지 읽어들이는 'r' 모드.
file = open('C:/*****/*****/*******/prime_num.txt', 'r')
print(f'2부터 {num}까지의 소수는 \n{file.read()}')
file.close()
===============================================================
0보다 큰 정수 입력 : 50
2부터 50까지의 소수는
2
3
5
7
11
13
17
19
23
29
31
37
41
43
47
with ~ as문
- 파일을 연 후 close()를 생략할 수 있다.
아래 예시와 같이 사용한다.
위에서 사용했던 소수를 찾아 txt파일에 입력하고, 읽어들이는 예제에
with ~ as 구문을 추가해보자.
def writePrineNum(n):
file = open('C:/*****/*****/prime_num.txt', 'a')
file.write(str(n))
file.write('\n')
file.close()
num = int(input('0보다 큰 정수 입력 : '))
for i in range(2, num+1):
flag = True
for j in range(2, i):
if i % j == 0 :
flag = False
break
if flag:
writePrineNum(i)
# with ~ as 구문을 사용하면 close()를 해 주지 않아도 되어 코드가 간단해진다.
with open('C:/*****/*****/prime_num.txt', 'r') as r:
print(f'2부터 {num}까지의 소수는 \n{r.read()}')
=============================================================
0보다 큰 정수 입력 : 50
2부터 50까지의 소수는
2
3
5
7
11
13
17
19
23
29
31
37
41
43
47