문법 또는 여러가지 이유로 오류가 발생하지만 오류를 무시하고 싶을 때 파이썬은 try, except를 사용해서 예외적으로 오류를 처리할 수 있게 해주는 것이 예외처리 입니다.
예외처리 형식은 다음과 같습니다.
try:
실행할 소스코드
except [발생 오류[as 오류 메시지 변수]]:
오류 일경우 출력 하고 싶다면 작성
예제 ZeroDivisionError - 0으로 나눌경우 예외처리
# 예외처리 try ~ except
def divide(a,b):
return a / b
try:
#c = divide(5,2)
c = divide(5,0)
except ZeroDivisionError:
print('두번째 숫자는 0을 빼고 주세요')
print('종료')
출력 결과
작업 후
두번째 숫자는 0을 주지 마시오
종료
소스코드에서 다음과 같은 함수를 주었습니다.
a / b 의 계산을 하는데 0으로 나눌경우 ZeroDivisionError라는 예외처리를 하였습니다.
c = divide(5,0)을 작성할 경우 5 나누기 0을 의미하는 거이기 떄문에 위의 에러로 인한 예외처리가 발생하였습니다.
0이 아닌 divide(5,2)를 주면 출력 결과는 당연히 예외처리 부분을 제외한 나머지가 출력될 것입니다.
예외처리 IndexError - 참조 범위 오류
# 예외처리 try ~ except
def divide(a,b):
return a / b
try:
aa = [1,2]
print(aa[0])
except IndexError as e:
print('참조 범위 오류 : ', e)
except Exception as err:
print('기타에러' + str(err))
print('종료')
이번에는 참조 범위를 벗어나면 예외처리를 해보겠습니다. 배열 aa는 1과 2를 저장하였고,
import os
print(os.getcwd())
출력 결과
자신이 사용하고 있는 파이썬 저장 경로가 출력됩니다
파일 읽기
파일을 불러올 txt 파일
ftest.txt
푸른하늘
은하수
하얀 쪽배에
import os
print(os.getcwd())
try:
print(os.getcwd())
print('파일 읽기')
f1 = open(r'ftest.txt', mode='r', encoding='utf-8') # open 장치 열고
print(f1.read())
f1.close()
except Exception as e:
print(e)
출력 결과
파일 읽기
푸른하늘
은하수
하얀 쪽배에
파일 저장
import os
print(os.getcwd())
try:
print(os.getcwd())
print('파일 저장 ')
f2 = open('ftest2.txt', mode='w', encoding='utf-8')
f2.write('kbs\n')
f2.write('월요일 아침\n')
f2.write('mbc11')
f2.close()
print('저장성공')
except Exception as e:
print(e)
출력 결과
파일 저장
저장성공
다음과 같이 출력이 되면서 해당 경로에
ftest2.txt 파일이 생성됩니다.
파일 추가
import os
print(os.getcwd())
try:
print(os.getcwd())
print('파일 추가')
f3 = open('ftest2.txt', mode='a', encoding='utf-8')
f3.write('sbs\n')
f3.write('홍길동\n')
f3.close()
print(' 추가 성공')
except Exception as e:
print(e)
출력 결과
파일 추가
추가 성공
위와 같은 출력 결과가 나타나면서 파일이 추가 된 것을 알 수 있습니다.
여러 종류의 객체 저장 및 읽는 방법은 pickle 외장 함수를 사용한다.
pickle 이란 ?
- 객체의 형태를 그대로 유지하고, 파일에 저장하고 읽기가 가능한 모듈이다.
import pickle
try:
dicdata = {'tom':'111-1111', '길동':'222-2222'}
listdata = ['마우스','키보드']
tupledata = (dicdata, listdata) # 복합 개체
with open('hi.dat', 'wb') as ff3:
pickle.dump(tupledata, ff3)
pickle.dump(listdata, ff3)
print('읽기')
with open('hi.dat', 'rb') as ff4:
a,b = pickle.load(ff4)
print(a)
print(b)
except Exception as err:
print('에러 : ',err)
출력 결과
{'tom': '111-1111', '길동': '222-2222'}
['마우스', '키보드']
소스코드에서 딕셔너리 자료와 리스트 자료를 만들고 튜플 자료에 두개의 개체를 넣어서 복합 개체로 정의해주었습니다.
그리고 그 파일자료를 읽으면 어떤 자료형이든저장하고 불러올 수 있고, 위와 같은 결과가 나타납니다.납니다.
class Person:
say = '안녕하세요 제 나이는 '
nai = 20
def __init__(self, nai):
print('Persion 생성자')
self.nai = nai
def PrintInfo(self):
print('이야기 :{} {}'.format(self.say, self.nai))
p = Person('22')
p.PrintInfo()
출력 결과
Persion 생성자
이야기 :안녕하세요 제 나이는 22
우선 Person 이라는 클래스를 생성하고, 생성자에 nai라는 변수를 주었습니다.
이후 p 객체를 생성하기 위에선 nai가 필요하기 때문에 나이를 22로 주었고 그에 따른 해당 출력 결과는
위와 같이 출력됩니다.
그럼 이제 자식 클래스를 만들어서 상속받아겠습니다.
class Student(Person):
say = '공부하는 '
subject = '학생'
def __init__(self):
print('Student 생성자생성')
def PrintInfo(self):
print('Student의 PrintInfo')
def EprintInfo(self):
print(self.say, ' ' , super().say)
super().PrintInfo() # super() 붙어서 처음부터 부모꺼
self.PrintInfo() # 자기꺼 있으면 자기꺼 없으면 부모꺼
e = Student()
print(e.say, ' ' , e.nai, '살 ' , e.subject)
e.EprintInfo()
출력 결과
Student 생성자생성
공부하는 20 살 학생
공부하는 안녕하세요 제 나이는
이야기 :공부하는 20
Student의 PrintInfo
소스코드를 보시면
Student 클래스는 Person 부모클래스로부터 상속 받고있습니다.
그리고 Student 생성자를 생성하는 함수가 작성되어있습니다. 여기서 생성자가 작성되어있지 않다면 부모 클래스의 생성자를 따라가게 되어있습니다. 그렇다면 부모클래스의 생성자는 nai를 받기 떄문에
Student 클래스에서 e 라는 변수로 객체를 생성할때 e = Student(나이값) 과 같이 나이 값을 넣어주어야 오류가 발생하지 않습니다.
EprintInfo() 함수에서 부모클래스의 say를 받아서 출력하는 것을 알 수 있습니다.
super() 여기서 super()는 부모클래스의 내용을 자식클래스에서 사용하고 싶은 경우 쓸 수 있습니다.
이번에는 다중 상속에 대해 알아보겠습니다.
다중 상속이란?
2개 이상의 클래스를 받아 사용하는 것을 뜻합니다.
우선 부모 클래스로 사용할 클래스 2개를 만들어보겠습니다.
class A:
data = '파이썬'
def Std(self):
print('파이썬 공부')
def Std1(self):
print('파이썬 공부는 재밌다.')
class B:
def Std(self):
print('자바 공부')
def dif(self):
print('자바 공부는 어렵다')
def kbs(self):
pass # 필수는 아니지만 다형성을 위해 강요 가능함
부모클래스 A와 B를 생성하였습니다.
이제 이 부모클래스를 호출할 자식 클래스를 만들어서 호출해보겠습니다.
class C(A, B):
pass
aa = C()
# 중복일 경우 먼저 상속한 값으로 가져옴 그래서 A.Std() 가져옴
aa.Std()
aa.Std1()
aa.dif()
print(aa.data)
출력 결과
파이썬 공부
파이썬 공부는 재밌다.
자바 공부는 어렵다
파이썬
자식클래스 C를 생성하였습니다.
부모 클래스 A에서 Std 함수가 존재하고 부모 클래스 B에도 Std 함수가 존재한다.
하지만 출력 결과를 보면 주석에도 언급하였듯, 먼저 상속받은 클래스의 함수를 출력 시키는 것을 알 수 있습니다.
이번에는 자식클래스 D를 만들어 C클래스와 반대로 해보겠습니다.
class D(B, A):
data = '프로그래밍 천국'
def Play(self):
self.Std()
super().Std()
def dif(self):
print('어려워도 열심히하려한다.')
bb = D()
# 중복일 경우 먼저 상속한 값으로 가져옴 그래서 B.Std() 가져옴
bb.Play()
bb.dif()
출력 결과
자바 공부
자바 공부
어려워도 열심히하려한다.
먼저 호출한 부모클래스의 함수를 가져오는 것을 알 수 있습니다.
추상 클래스
추상 클래스란?
추상 클래스는 기본골격을 만들고 상속받는 클래스에서 그 구현을 강제로 시키는 클래스입니다.
형식을 다음과 같습니다.
from abc import *
class 추상클래스이름(metaclass=ABCMeta):
@abstractmethod
def 추상메소드(self):
pass
바로 예제로 들어가도록 하겠습니다.
추상클래스 AbstractCalss
from abc import *
class AbstractClass(metaclass=ABCMeta):
# ABCMeta 클래스의 서브 클래스는 추상 클래스
@abstractclassmethod
def abcMethod(self): # 추상 메소드
pass
def normalMethod(self):
print('AbstractClass 클래스의 일반 메소드')
이 추상 클래스를 받아서 사용할 Child1 클래스
class Child1(AbstractClass):
name = 'Child1입니다.'
def abcMethod(self):
print('추상메소드를 오버라이딩')
c1 = Child1()
print(c1.name)
c1.abcMethod()
c1.normalMethod()
출력 결과
Child1입니다.
추상메소드를 오버라이딩
AbstractClass 클래스의 일반 메소드
AbstractClass 추상클래스에서 abcMethod를 추상메소드로 주었고,
Child1 클래스에서 위 추상클래스를 받아서 사용 하도록 하였습니다.
위와 같이 작성하면 추상클래스의 미구현 메소드를 받아 사용하였기 때문에 아무런 문제가 없이 잘 출력됩니다.
이번에는 추상클래스를 좀 더 자세히 보기 위해 Child1 클래스에서 받았던 미구현 추상메소드를 지워보겠습니다.
class Child1(AbstractClass):
name = 'Child1입니다.'
c1 = Child1()
print(c1.name)
c1.abcMethod()
c1.normalMethod()
그럼 다음과 같은 오류 메세지를 출력합니다.
이러한 에러를 출력하는 이유는 임포트 과정에서 에러를 출력하진 않지만 추상클래스에서 미구현 메소드를 Child1 클래스에서 받지 않고 객체 생성을 하려했기 때문에 객체 생성 과정에서 오류가 발생하는 것입니다.
class Animal: # 부모클래스
def __init__(self):
print('animal 생성자')
def move(self):
print('움직이는 동물')
class Dog(Animal): # 자식클래스
def __init__(self): # 해당 클래스의 생성자가 없으면 부모 생성자를 부르고 생성자가 있으면 자신을 호출한다.
print('Dog 생성자')
def my(self):
print('나는 개')
dog1 = Dog()
dog1.my()
dog1.move()
출력 결과
Dog 생성자
나는 개
움직이는 동물
부모클래스 Aninal의 '움직이는 동물'을 자식클래스 Dog가 가져다가 사용하여 위와 같은 출력 결과를 가지고 온 것을 알 수 있습니다.
여기서 부모클래스의 생성자를 가지고 오지 않는 이유는 주석에도 알 수 있듯이, 자식클래스에서 생성자가 있기 때문입니다.
오버라이딩
- 부모 클래스의 메소드를 자식 클래스에서 재정의 하는 것입니다.
다형성
- 부모 클래스로부터 물려받은 내용을 자식 클래스 내에서 오버라이딩하여 사용하는 것입니다.
class Parent: # overriding
def Prindata(self):
pass
class Child1(Parent):
def Prindata(self):
print('Child1에서 overrding')
class Child2(Parent):
def Prindata(self):
print('Child2에서 재정의')
def abc(self):
print('Child2 고유 메소드')
c1 = Child1()
c1.Prindata()
c2 = Child2()
c2.Prindata()
출력 결과
Child1에서 overrding
Child2에서 재정의
부모클래스인 Child1 에서 Printdata 메소드는 'child1에서 overrding'을 출력해준다.
하지만 오버라이딩 성질을 이용하면 Child2에서 Printdata 메소드의 출력문인 'Child2에서 재정의' 를 출력해줍니다.
# 모듈의 멤버로 클래스
class TestClass:
kk = 1 # 멤버변수 ( 전역 )
def __init__(self):
print('생성자')
def __del__(self):
print('소멸자')
def printMsg(self): # 메소드 (public)
name = '한국인' # 지역변수
print(name)
print(self.kk)
test = TestClass() # 생성자 호출. instance
print(test.kk) # 1을 출력
print(TestClass.kk) # prototype(원형) 클래스의 멤버 직접 호출
print()
test.printMsg() # Bound Method call
# TestClass.printMsg() # 이렇게 주면 아규먼트를 주지 않아서 ERR
print()
TestClass.printMsg(test) # UnBound Method call
출력 결과
생성자
1
1
한국인
1
한국인
1
소멸자
# Bound Method Call는 self가 붙은 쪽에 사용하고, UnBound Method Call 이란 self 를 안 붙은 쪽을 말합니다.
파이썬에서 사용하는 특별한 메소드
# __init__ :
- 초기화(initialize) 메서드라고도 합니다.
- 어떤 클래스의 객체가 만들어질 때 자동으로 호출되어서 그 객체가 갖게 될 여러 가지 성질을 정해주는 역할을 함
- 위 소스에서는 TestClass() 를 작성하여 TestClass 객체를 생성하자마자 초기화가 되고 '생성자'를 출력하였습니다.
# __del__ :
- 객체가 없어질때 사용하는 메소드입니다.
- 위 소스에서는 그래서 맨 마지막에 '소멸자'가 출력되었습니다.
이번에는 __init__ 메소드에 인자를 받아야만 생성자가 생성되는 예제를 들어보겠습니다.
class Car:
handle = 0
speed = 0
def __init__(self, name, speed):
self.speed = speed
self.name = name
def showData(self):
km = '킬로미터'
msg = '속도:' + str(self.speed) + km
return msg
print(Car.handle)
print(Car.speed)
#print(Car.name) # type object 'Car' has no attribute 'name'
print()
car1 = Car('tom',10)
print(car1.handle, car1.name, car1.speed)
print('------')
car2 = Car('james',20)
print(car2.handle, car2.name, car2.speed)
print()
print(car1.showData())
print(car2.showData())
car1.speed = 88
car2.speed = 100
print(car1.showData())
print(car2.showData())
Car.handle = 1
print(car1.handle)
print(car2.handle)
출력 결과
0
0
0 tom 10
------
0 james 20
속도:10킬로미터
속도:20킬로미터
속도:88킬로미터
속도:100킬로미터
1
1
위 소스코드는 __init__ 생성자에 self, name, speed 를 주었기 때문에 새로운 객체를 생성할때 name,과 speed를 가지고 가야 생성이 가능합니다. 그렇지 않으면 다음과 같은 에러를 출력합니다.
car1 객체와 car2 객체를 생성 한 후에는 speed 값을 기존 10에서 각각 88과 100으로 변경해주었습니다.
그 출력 결과 속도들의 변경된 점을 확인 가능했습니다.
# 클래스는 포함자원의 재활용 목적으로 다른 클래스를 불러다가 사용 가능합니다.
handle.py
# 다른 클래스에서 공유할 클래스
class PohamHandle:
quantity = 0
def LeftTurn(self, quantity): # self에 quantity 가 들어옴
self.quantity = quantity
return '좌로 돌아';
def RightTurn(self, quantity): # self에 quantity 가 들어옴
self.quantity = quantity
return '우로 돌아';
PohanCar.py
import etc.handle
class PohanCar:
turnShow = '정지'
def __init__(self, ownerName):
self.ownerName = ownerName
self.handle = etc.handle.PohamHandle()
def TurnHandle(self, q):
if q > 0:
self.turnShow = self.handle.RightTurn(q)
elif q < 0:
self.turnShow = self.handle.LeftTurn(q)
else:
self.turnShow = '직진'
if __name__ == '__main__':
tom = PohanCar('tom')
tom.TurnHandle(10)
print(tom.ownerName + ' 의 회전량은 ' + tom.turnShow + str(tom.handle.quantity))
print()
james = PohanCar('james')
james.TurnHandle(0)
print(james.ownerName + ' 의 회전량은 ' + james.turnShow + str(james.handle.quantity))
# 함수 장식자(decorator
def make2(fn):
return lambda:'파이썬 ' + fn() # '파이썬'과 fn() 함수를 합쳐서 리턴
def make1(fn):
return lambda:'공부를 '+fn()
def hello():
return '열심히'
hi = make2(make1(hello))
print(hi())
# 출력 결과
파이썬 공부를 열심히
기존 hello() 함수는 '열심히' 만을 반환하는 함수입니다.
하지만 이 함수를 mak1이라는 함수에 씌워주고, 그 겉에는 또 다시 make2라는 함수로 덮어주었습니다.
그 말은 make2함수의 '파이썬'을 출력하고 그 안에 호출할 함수 make1 에서 '공부를' 호출 후 hello의 '열심히' 를 호출하게 됩니다.
위와 같은 방법이 아닌 다른 방법으로는 '@' 키워드를 사용하여도 적용 가능합니다.
함수를 데코레이션('@')으로 사용할 경우
def make6(fn):
return lambda:'공부를 '+fn()
@make6
def hello1():
return '열심히'
print((hello1()))
# 출력 결과
공부를 열심히
클래스를 데코레이션('@') 으로 사용할 경우
class prac(object):
def __init__(self, fn):
self.fn = fn
def __call__(self, *args, **kwargs):
result = self.fn(*args, **kwargs)
print(f'Result: {result}')
return result
@prac
def add(a, b):
return a + b
add(5,1)
# 출력 결과
Result: 6
def fun1(a, b):
return a + b
fun2 = fun1
print(fun2(3,4))
def fun3(func):
def fun4(): # 함수 안에 함수
print('내부함수 출력')
fun4()
return func # 반환값이 함수
abc = fun3(fun1) # 인자로 함수 전달
출력 결과
7
내부함수 출력