객체를 이용한 프로그램으로 객체는 속성과 기능으로 구성됨
ex. 계산기(객체)
속성 : 숫자 / 기능 : 덧셈,뺄셈
ex. 자동차(객체)
속성 : 색상, 길이, 가격 / 기능 : 전진,후진,정지
즉, 객체(object) = 속성(attribute) + 기능(function)
장점
코드 재사용 및 모듈화에 좋음
객체는 클래스에서 생성됨
즉 하나의 클래스를 만들어두면 여러개의 객체를 만들 수 있음
ex. 자동차 클래스
속성 : 색상,길이,가격
기능 : 전진,후진,정지
이후에 여러 자동차 객체를 찍어낼 수 있음
class Car: #클래스는 변수명을 대문자로 만드는게 관례임
def __init__(self,col,len): #생성자,속성
self.color = col
self.length = len
def doStop(self): #기능
print('stop')
def doStart(self): #기능
print('start')
class Car: #클래스는 변수명을 대문자로 만드는게 관례임
def __init__(self,col,len): #생성자,속성
self.color = col
self.length = len
def doStop(self): #기능
print('stop')
def doStart(self): #기능
print('start')
def carInfo(self):
print(f'color : {self.color})
print(f'length : {self.length})
위와 같은 Car 라는 클래스가 생성된 후엔 아래와 같이 객체를 만듬
car1 = Car('red',200) #빨간, 200길이의 차
car2 = Car('blue',300)
car1.carInfo
car2.carInfo
car1.doStart
2개의 객체가 생성된 것임
class NewPc:
def __init__(slef, n, cpu, mem, ssd):
self.name = n
self.cpu = cpu
self.memory = mem
self.ssd = ssd
def doExcel(self):
print('excel run')
def doPhoto(self):
print('photoshop run')
def pcInfo(self):
print(f'name : {self.name}')
print(f'cpu : {self.cpu}')
print(f'memory : {self.memory}')
print(f'ssd : {self.ssd}')
위와 같이 클래스를 먼저 생성
myPc = NewPc('my pc','i5','16G','256G')
myPc.pcInfo()
friendPc = NewPc('friendPc','i6','18G','512G')
friendPc.pcInfo()
my pc와 friendPc 를 비교해 보았을 때 친구 pc가 더 좋음.
나도 더 좋아지고 싶음
myPc.cpu = 'i9'
myPc.memory = '32G'
myPc.ssd = '1T'
myPc.pcInfo()
이후에 객체를 새로운 값으로 정의하고 변경하면 됨.
클래스를 만들고 해당 데이터에 대한 주소만 복사하고 싶다면 얕은 복사가 가능함
<예시>
calss명 : Temcls
tc1 = Temcls(10,'blue')
tc2 = tc1
여기서 만약에 tc2를 바꾼다면 tc1도 바꿈
tc2.number = 12
tc2.color = 'red'
클래스를 만들고 데이터에 대한 주소만 복사하는 것이 아닌, 또 다른 하나의 객체로 존재하게 됨
깊은 복사 사용 방법
import copy
<방법 1>
tc1 = Temcls(10,'blue')
tc2 = copy.copy(tc1)
<방법2>
scores = [9, 7, 2, 3]
scoresCopy = []
scoresCopy = scores
for s in scores:
scoresCopy.append(s)
<방법3>
scoresCopy.extend(scores)
<방법4>
scoresCopy = scores.copy()
<방법5>
scoresCopy = scores[:]
클래스는 또 다른 클래스를 상속해서 내 것처럼 사용할 수 있음
class NormalCar:
def drive(self):
print('[NormalCar]drive() called')
def back(self):
print('[NormalCar]back() called')
class TurboCar(NormalCar):
def turbo(self):
print('[TurboCar]turbo() called')
turboCar = TurboCar()
turboCar.turbo()
turboCar.back()
turboCar.drive()
---------------------------
[TurboCar]turbo() called
[NormalCar]back() called
[NormalCar]drive() called
객체가 생성될 때 생성자를 호출하면 init()가 자동 호출됨
class Cal:
def __init__(self):
print('__init__ called')
cal = Cal()
__________________________
__init__ called
init()가 속성을 초기화 함
<예시1>
class Cal:
def __init__(self,n1,n2):
print('__init__ called')
self.num1 = n1
self.num2 = n2
cal = Cal(10,20)
print(f'cal.num1 : {cal.num1}')
print(f'cal.num2 : {cal.num2}')
------------------------------------
<예시2>
class Cal:
def __init__(self):
print('__init__ called')
self.num1 = 10
self.num2 = 100
cal = Cal()
print(f'cal.num1 : {cal.num1}')
print(f'cal.num2 : {cal.num2}')
______________________________________
<예시3>
class Cal:
def __init__(self,n):
print('__init__ called')
self.num1 = n
self.num2 = 100
cal = Cal(3.14)
print(f'cal.num1 : {cal.num1}')
print(f'cal.num2 : {cal.num2}')
super()
상속을 하면 최초 클래스는 초기화가 됨
<예시>
class P_Class:
def __init__(self,n1,n2):
print('[P_Class] __init__() called')
self.num1 = n1
self.num2 = n2
class C_Class(P_Class):
def __init__(self, n1, n2):
print('[C_Class] __init__() called')
self.num1 = n1
self.num2 = n2
cls = C_Class(10,20)
_______________________________
[C_Class] __init__() called
만약 P_Class도 호출하고 싶다면?
<예시1>
class P_Class:
def __init__(self,n1,n2):
print('[P_Class] __init__() called')
self.num1 = n1
self.num2 = n2
class C_Class(P_Class):
def __init__(self, n1, n2):
print('[C_Class] __init__() called')
P_Class.__init__(self,n1,n2) #강제로 불러오기
self.num1 = n1
self.num2 = n2
cls = C_Class(10,20)
<예시2>
class P_Class:
def __init__(self,n1,n2):
print('[P_Class] __init__() called')
self.num1 = n1
self.num2 = n2
class C_Class(P_Class):
def __init__(self, n1, n2):
print('[C_Class] __init__() called')
super().__init__(n1,n2)
self.num1 = n1
self.num2 = n2
cls = C_Class(10,20)
super()를 쓰면 상위 속성을 불러와서 사용할 수 있음.
super()는 self쓰지 않아도 됨.
하나의 클래스 안에 2개 이상의 클래스를 상속할 수 있음
class Car01:
def drive(self):
print('drive() method called')
class Car02:
def turbo(self):
print('turbo() method called')
class Car03:
def fly(self):
print('fly() method called')
class Car(Car01,Car02,Car03):
def __init__(self):
pass
myCar = Car()
myCar.fly()
myCar.turbo()
하위 클래스에서 상위 클래스의 메서드를 재정의함.
예 :
로봇 클래스 안에 fire() : 총알발사
뉴 로봇 클래스 안에 fire() : 레이저 발사로 바꾸는 것
class Robot:
def __init__(self, c, h, w):
self.color = c
self.height = h
self.weight = w
def fire(self):
print('미사일 발사')
def printInfo(self):
print(f'색상 : {self.color}')
print(f'높이 : {self.height}')
print(f'무게 : {self.weight}')
class NewRobot(Robot):
def __init__(self, c, h, w):
super().__init__(c,h,w)
def fire(self):
print('레이저 발사')
myRobot = NewRobot('red', 200, 300)
myRobot.printInfo()
myRobot.fire()
-------------------------------
색상 : red
높이 : 200
무게 : 300
레이저 발사
상위 클래스에서 하위 클래스에 메서드 구현을 강요함.
예 : 선언만 되어 있던 클래스를 하위 클래스에서 구현하도록 하게함.
추상 클래스 사용을 위해선 아래 모듈을 불러와야함
from abc import ABCMeta
from abc import abstractmethod
그리고 필수로 구현하게 하고 싶은 것에 @abstractmethod 사용
다른 클래스에 상속하더라도 그 클래스에도 필수 메서드를 써야함
from abc import ABCMeta
from abc import abstractmethod
class Airplane(metaclass=ABCMeta):
@abstractmethod
def flight(self): #상속 받는 애가 반드시 구현하게 하고 싶음
pass
def forward(self):
print('전진')
def backward(self):
print('후진')
class Airliner(Airplane):
def __init__(self,c):
self.color = c
def flight(self):
print('시속 400 비행')
al = Airliner('red')
al.flight()
al.forward()
예상하지 못한 문제로 프로그램 실행이 어려운 상태(문법적인 문제는 없음)
에러와는 다름(에러는 문법적,네트워크 등의 문제)
def add(n1,n2):
print(n1+n2)
def div(n1,n2):
print(n1/n2)
firstNum = int(input('n1 : '))
secondNum = int(input('n2 : '))
add(firstNum,secondNum)
div(firstNum,secondNum)
-------------------------------
n1 : 10
n2 : 0
10
ZeroDivisionError: division by zero
ZeroDivisionError: division by zero 처럼 0을 나눌 수 없을 때 나오는 것!
예외 종류
🔹 1. 문법 관련 예외
SyntaxError 문법 오류 (예: 괄호 닫힘 누락 등)
IndentationError 들여쓰기 오류
TabError 탭과 스페이스 혼용 등으로 생긴 들여쓰기 오류
🔹 2. 이름 및 참조 오류
NameError 정의되지 않은 변수나 함수 사용
UnboundLocalError 지역 변수 참조 전에 할당하지 않은 경우 (NameError의 하위 클래스)
🔹 3. 타입 및 값 오류
TypeError 잘못된 타입의 값 사용 (예: 숫자 + 문자열)
ValueError 타입은 맞지만 부적절한 값 사용 (예: int("abc"))
🔹 4. 인덱스 및 키 관련
예외명 설명
IndexError 리스트/튜플 등에서 존재하지 않는 인덱스 접근
KeyError 딕셔너리에 존재하지 않는 키 접근
🔹 5. 파일 및 입출력
예외명 설명
FileNotFoundError 존재하지 않는 파일 열기 시도
IOError (또는 OSError) 입출력 작업 중 오류 발생 (파일, 디스크 등)
🔹 6. 숫자 연산 오류
ZeroDivisionError 0으로 나누기 시도
OverflowError 수치 계산 결과가 너무 커서 표현 불가능할 때
FloatingPointError 부동소수점 연산 오류 (일반적으로 직접 발생시키지 않음)
🔹 7. 속성 및 모듈 오류
AttributeError 존재하지 않는 속성 접근
ImportError 모듈을 불러올 수 없을 때
ModuleNotFoundError 존재하지 않는 모듈을 import할 때 (ImportError 하위 클래스)
🔹 8. 기타 예외
AssertionError assert 문 실패 시 발생
NotImplementedError 아직 구현되지 않은 메서드를 호출할 때
RuntimeError 다른 구체적인 에러로 설명할 수 없는 일반적인 실행 오류
StopIteration next()에서 더 이상 반환할 것이 없을 때
KeyboardInterrupt 사용자(보통 Ctrl+C)에 의해 인터럽트 발생
예외가 프로그램 전체 실행에 영향이 없도록 처리함
프로그램을 실행 중 중간에 예외가 발생하면 멈추게되니 중간 예외가 발생해도 종료까지 진행되도록 하는 것
try~except
<예시>
n1 =10; n2 = 0
print(n1/n2)
print(n1*n2)
print(n1-n2)
-----------------------
print(n1/n2)
~~^~~
ZeroDivisionError: division by zero
이렇게 예외가 발생하게 되었을 때 해결하는 방법
<예시>
n1 =10; n2 = 0
try:
print(n1/n2)
except:
print('예상치 못한 예외가 발생했습니다.')
print('다음 프로그램은 정상 실행')
print(n1*n2)
print(n1-n2)
----------------------------------
예상치 못한 예외가 발생했습니다.
다음 프로그램은 정상 실행
0
10
예문 : 숫자만 포함되는 리스트 만들기
nums = []
n = 1
while n < 6:
try:
num = int(input('입력 : '))
except:
print('예외 발생')
continue
nums.append(num)
n += 1
print(f'{nums}')
try~except~else
예외가 발생하지 않은 경우 실행하는 구문
즉, try구문이 정상적으로 진행되면 실행하도록 하는 구문.
<예시> 짝수만 리스트에 넣기
nums = []
n = 1
while n < 6:
try:
num = int(input('입력 : '))
except:
print('예외 발생')
continue #컨티뉴로 1회로 치지 않도록하기
else:
if num % 2 == 0:
nums.append(num)
n+=1
else:
print('입력한 숫자는 홀 수 입니다.')
print('다시 입력하세요.')
continue
print(f'{nums}')
<예시2> 짝수, 홀수, 소수 구분하기
even = []; odd = []; floatlist = []
n = 1
while n <= 5:
try:
num = float(input('입력 : '))
except:
print('숫자만 입력하세요!')
continue
else:
if num - int(num) != 0:
floatlist.append(num)
else:
if num % 2 == 0:
even.append(int(num))
else:
odd.append(int(num))
n += 1
print(even)
print(odd)
print(floatlist)
finally
예외 발생과 상관없이 항상 실행함.
<예시> 어떤 정보를 입력하던지 입력데이터를 보여준다
try:
inputData = input('num : ')
numInt = int(inputData)
except:
print('예외 발생! 숫자가 아닙니다.')
else:
if numInt % 2 == 0:
print('짝수')
else:
print('홀수')
finally:
print(f'입력 데이터 : {inputData}')
<예시2> 짝수,홀수,소수리스트를 보여주고, 입력한 데이터를 전체 보여줘
even = []; odd = []; floatlist=[]; datalist = []
n = 1
while n <=5:
try:
inputData = input('num : ')
floatData = float(inputData)
except:
print('예외 발생! 숫자가 아닙니다.')
continue
else:
if floatData - int(floatData) != 0:
print('소수')
floatlist.append(floatData)
else:
if floatData % 2 == 0:
print('짝수')
even.append(int(floatData))
else:
print('홀수')
odd.append(int(floatData))
n+=1
finally:
datalist.append(inputData)
print(f'입력 데이터 : {datalist}')
print(f'짝수 : {even}')
print(f'홀수 : {odd}')
print(f'소수 : {floatlist}')
예외를 담당하는 클래스 > Exception
<예시>
n1 = int(input('n1 : '))
n2 = int(input('n2 : '))
try:
print(f'n1 / n2 = {n1 / n2}')
except Exception as error:
print('0ㅇ으로 나눌 수 없습니다.')
print(f'exceoption : {error}')
------------------------------
n1 : 10
n2 : 0
0ㅇ으로 나눌 수 없습니다.
exceoption : division by zero
except Exception 를 사용하면 무슨 예외가 발생했는지 알 수 있음
Exception — 모든 예외의 최상위 클래스
ValueError, TypeError 같은 예외들의 부모 클래스
커스텀 예외를 만들거나, 모든 예외를 포괄하고 싶을 때 사용해
raise : 강제로 예외를 발생시키는 것
def divCalculator(n1, n2):
if n2 != 0:
print(f'{n1} / {n2} = {n1 / n2}')
else:
raise Exception('0으로 나눌 수 없습니다.') #예외를 강제로 만들어 냄
num1 = int(input('input number1: '))
num2 = int(input('input number2: '))
try:
divCalculator(num1, num2)
except Exception as e:
print(f'Exception: {e}')
num2에 0이 들어가고, try~except 구문이 없다면 실행이 중단되면서 예외가 발생됨.
그래서 try~except 구문을 넣어서 만들어둔 예외 코드를 출력함
<예시> 글자 수에 따라 sms,mms 발송됨
def sendSMS(msg):
if len(msg) > 10:
raise Exception('길이 초과!! MMS전환 후 발송!!', 1)
else:
print('SMS 발송!!')
def sendMMS(msg):
if len(msg) <= 10:
raise Exception('길이 미달!! SMS전환 후 발송!!', 2)
else:
print('MMS 발송!!')
msg = input('input message: ')
try:
sendSMS(msg)
except Exception as e:
print(f'e: {e.args[0]}') # 에러 메시지
print(f'e: {e.args[1]}') # 전환 번호
if e.args[1] == 1:
sendMMS(msg) # 길이 초과 → MMS 전환
elif e.args[1] == 2:
sendSMS(msg) # 길이 미달 → SMS 전환
사용자가 사용할 예외 클래스를 만들고 그걸 사용할 수 있음
class 이름 아무거나(Except)를 받아주면됨
<예시>
#사용자 정의 예외 클래스
class NotUseZeroException(Exception):
def __init__(self, n):
super().__init__(f'{n}은 사용할 수 없습니다!!')
#계산 함수
def divCalculator(num1, num2):
if num2 == 0:
raise NotUseZeroException(num2)
else:
print(f'{num1} / {num2} = {num1 / num2}')
#사용자 입력 및 예외 처리
num1 = int(input('input number1: '))
num2 = int(input('input number2: '))
try:
divCalculator(num1, num2)
except NotUseZeroException as e:
print(e)
<예시>
class PasswordLengthShortException(Exception):
def __init__(self,pw):
super().__init__(f'{pw} : 길이 5미만!')
class PasswordLengthLongException(Exception):
def __init__(self,pw):
super().__init__(f'{pw} : 길이 10초과!')
class PasswordWrongException(Exception):
def __init__(self,pw):
super().__init__(f'{pw} : 잘못된 비밀번호')
n=1
while n < 6:
pw = input('비밀번호 : ')
try:
if len(pw) < 5:
raise PasswordLengthShortException(pw)
elif len(pw) > 10:
raise PasswordLengthLongException(pw)
elif pw == 'admin1234':
print('비밀번호 확인 완료!')
break
else:
raise PasswordWrongException(pw)
except (PasswordLengthShortException, PasswordLengthLongException, PasswordWrongException) as e:
print(f'{e}')
n += 1
else:
print('비밀번호 5회 이상 오입력')