[python] 클래스 / 텍스트 파일 읽기, 쓰기

jane05·2023년 9월 10일
0
post-thumbnail

2️⃣ 파이썬 중급

17. 객체지향 프로그래밍

  • 객체지향 프로그래밍: 객체를 이용한 프로그램으로 객체는 속성과 기능으로 구성된다.

  • 객체(object) = 속성(attribute) + 기능(function)

  • 예시

    • 계산기
      • 속성: 숫자
      • 기능: 덧셈, 뺄셈
    • 자동차
      • 속성: 색상, 길이, 가격
      • 기능: 전진, 후진, 정지
  • 객체는 클래스(class)에서 생성된다.

  • '클래스': 하나의 틀(클래스를 만들어두고 필요할 때마다 호출해서 사용) -> 붕어빵틀

  • '객체'는 무한대로 생성 -> 붕어빵

  • 객체 사용의 장점
    : 코드 재사용, 모듈화에 좋다.

  • 배터리 교체형(부품 결합도 낮음: 배터리만 교체해주면 됨)

  • 배터리 충전형(부품 결합도 높음: 일체형보다는 좋지만 교체형보다 떨어짐)

  • 배터리 일체형(부품 결합도 높음: 배터리가 닳으면 새로운 차 생산 필요)

18. 클래스와 객체 생성

  • 객체지향 프로그래밍: 객체를 이용한 프로그램으로, 객체는 속성과 기능으로 구성된다.
  1. 클래스(class) 만들기
  • 클래스는 class 키워드와 속성(변수), 그리고 기능(함수)를 이용해서 만든다.
  • 조건: 클래스 첫 글자는 '대문자'로 하기
class Car:
	
    def __init__(self, col, len): #init 메서드: 초기화 메서드 -> 생성자
    	self.color = col
        self.length = len
        
    def doStop(self): #self는 Car라는 클래스 안에 doStop이라는 기능이 들어있음을 의미한다.
    	print('STOP!!')
    def doStart(self):
    	print('START!!')
        
    def printCarInfo(self):
        print(f'self.color: {self.color}')
        print(f'self.length: {self.length}')
  1. 객체 생성: 객체는 클래스의 생성자를 호출한다.
#레퍼런스 변수
#1) 객체 생성
car1 = Car('red', 200)
car2 = Car('blue', 300)

#2) 객체 호출
car1.printCarInfo()
car2.printCarInfo()

car1.doStop()
car1.doStart()

19. 객체 속성 변경

  • 객체의 속성은 변경할 수 있다.
class NewGenerationPC:

    def __init__(self, name, cpu, memory, ssd):
        self.name = name #속성 정의하기
        self.cpu = cpu
        self.memory = memory
        self.ssd = ssd

    #기능 정의
    def doExcel(self):
        print('EXCEL RUN!!')

    def doPhotoshop(self):
        print('PHOTOSHOP RUN!!')

    def printPCInfo(self):
        print(f'self.name: {self.name}')
        print(f'self.cpu: {self.cpu}')
        print(f'self.memory: {self.memory}')
        print(f'self.ssd: {self.ssd}')

#객체 생성 및 호출
myPC = NewGenerationPC('myPc', 'i5', '16G', '256G')
myPC.printPCInfo()

#객체 생성 및 호출
friendPC = NewGenerationPC('friendPc', 'i7', '32G', '512G')
friendPC.printPCInfo()

#객체 속성 변경: 도트 접근 연산자를 이용해서 속성에 접근 가능!!
myPC.cpu = 'i9'
myPC.memory = '64G'
myPC.ssd = '1T'
myPC.printPCInfo()
class Calculator:
	
    def __init__(self): #인수를 따로 넣어주지 않는다.
    	self.number1 = 0
        self.number2 = 0
        self.result = 0
    
    def add(self):
    	self.result = self.number1 + self.number2
        return self.result
        
    def sub(self):
        self.result = self.number1 - self.number2
        return self.result

    def mul(self):
        self.result = self.number1 * self.number2
        return self.result

    def div(self):
        self.result = self.number1 / self.number2
        return self.result


cal = Calculator() #클래스를 인스턴스화 해주고 싶다면 추가하기: 내부 실행 시 불필요!
cal.number1 = 10
cal.number2 = 20

print(f'Calculator.add() : {cal.add()}')
print(f'Calculator.sub() : {cal.sub()}')
print(f'Calculator.mul() : {cal.mul()}')
print(f'Calculator.div() : {cal.div()}')

>>>
Calculator.add() : 30
Calculator.sub() : -10
Calculator.mul() : 200
Calculator.div() : 0.5

20. 객체와 메모리

  • 변수는 객체의 '메모리 주소'를 저장하고 이를 이용해서 '객체를 참조'한다.
  • 변수에는 객체가 직접 저장이 되지 않고, 메모리 주소가 변수에 저장된다.
  • 변수 안에 저장된 '메모리 주소값'을 찾아 객체를 참조한다. -> 레퍼런스 변수
#실습하기
#국어, 영어, 수학 점수를 입력받아 리스트에 저장하고 원본을 유지한 상태로,
#복사본을 만들어 과목별 점수를 10% 올렸을 경우에 평균을 출력해 보자.

scores = [int(input('국어 점수 입력: ')),
          int(input('영어 점수 입력: ')),
          int(input('수학 점수 입력: '))]

print(scores)

#copy 함수를 사용하면 주소가 아니라 실제 객체가 복사 된다. -> 독립성 유지
copyScores = scores.copy()

for idx, score in enumerate(copyScores):
	result = score * 1.1
    copyScores[idx] = 100 if result > 100 else result

print(f'이전 평균: {sum(scores) / len(scores)})
print(f'이후 평균: {sum(copyScores) / len(copyScores)}')

21. 얕은 복사 vs. 깊은 복사

  • 얕은 복사: 객체 주소를 복사하는 것으로, 객체 자체가 복사되지 않는다.
  • 깊은 복사: 객체 자체를 복사하는 것으로, 또 하나의 객체가 만들어진다. -> object
import copy

scores = [9,8,5,7,6,10]
scoresCopy = []

#얕은 복사
scoresCopy = scores

print(f'id(scores): {id(scores)}')
print(f'id(scoresCopy): {id(scoresCopy)}')

>>>
id(scores): 4375891584
id(scoresCopy): 4375891584


#깊은 복사 방법1: for 문
for s in scores: #scores는 전혀 다른 리스트이고, 그 안에 값만 복사
    scoresCopy.append(s)
print(f'id(scores): {id(scores)}')
print(f'id(scoresCopy): {id(scoresCopy)}') #값은 똑같지만 id값이 다르다.

#깊은 복사 방법2: extend 활용
scoresCopy.extend(scores)
print(f'id(scores): {id(scores)}') #값은 똑같지만 id값이 다르다.

# #깊은 복사 방법3: copy 함수 활용
scoresCopy = scores.copy()
print(f'id(scores): {id(scores)}')
print(f'id(scoresCopy): {id(scoresCopy)}') #값은 똑같지만 id값이 다르다.

#깊은 복사 방법4: 맨앞에서 맨끝까지 슬라이싱한 데이터를 할당
scoresCopy = scores[:]
print(f'id(scores): {id(scores)}')
print(f'id(scoresCopy): {id(scoresCopy)}') #값은 똑같지만 id값이 다르다.

>>>
id(scores): 4378284992
id(scoresCopy): 4378283200
id(scores): 4378284992
id(scores): 4378284992
id(scoresCopy): 4378285056
id(scores): 4378284992
id(scoresCopy): 4378283200
#실습하기
#선수의 원본 점수를 이용해서 평균을 출력하고, 최고값과 최저값을 제외한 평균을 출력하는 프로그램을 만들어보자.

plaOriSco = [8.7, 9.1, 8.9, 9.0, 7.9, 9.5, 8.8, 8.3]
plaCopSco = plaOriSco.copy()

plaOriSco.sort()

plaCopSco.sort() #정렬
plaCopSco.pop(0) #리스트형 데이터 변수의 인덱스 값 0에 위치해 있은 값을 삭제 및 반환 #최솟값 삭제
plaCopSco.pop() #리스트 맨 마지막 값, 즉 최대값 삭제

print(f'plaOriSco: {plaOriSco}')
print(f'plaCopSco: {plaCopSco}')

oriTot = round(sum(plaOriSco), 2)
oriAvg = round(oriTot / len(plaOriSco), 2)
print(f'Original Total: {oriTot}')
print(f'Original Average: {oriAvg}')

copTot = round(sum(plaCopSco), 2)
copAvg = round(oriTot / len(plaCopSco), 2)
print(f'Copy Total: {copTot}')
print(f'Copy Average: {copAvg}') #의문

print(f'oriAvg - copAvg: {oriAvg - copAvg}')

>>>
plaOriSco: [7.9, 8.3, 8.7, 8.8, 8.9, 9.0, 9.1, 9.5]
plaCopSco: [8.3, 8.7, 8.8, 8.9, 9.0, 9.1]
Original Total: 70.2
Original Average: 8.78
Copy Total: 52.8
Copy Average: 11.7
oriAvg = copAvg: -2.92

22. 클래스 상속

  • 클래스는 또 다른 클래스를 상속해서 내 것처럼 사용할 수 있다.
#실습하기1
#덧셈, 뺄셈 기능이 있는 클래스를 만들고, 이를 상속하는 클래스를 만들어서 곱셈과 나눗셈 기능을 추가해 보자.

class CalculaterSuper:

    def add(self, n1, n2):
        return n1 + n2

    def sub(self, n1, n2):
        return n1 - n2

class CalculatorChild(CalculaterSuper):

    def mul(self, n1, n2):
        return n1 * n2

    def div(self, n1, n2):
        return n1 / n2

myCalculator = CalculatorChild() #뒤에 있는 클래스가 상속을 받음

print(myCalculator.add(10,20)) #기능 상속 받음
print(myCalculator.sub(10,20)) #기능 상속 받음
print(myCalculator.mul(10,20))
print(myCalculator.div(10,20))

23. ~ 24. 생성자 / super()

  • 생성자: 객체가 생성될 때 생성자를 호출하면 init()가 호출된다. #init 메서드
class Calculator:

    def __init__(self):
        print('[Calculator] __init__() called!!')

cal = Calculator()

#__init__()가 속성을 초기화한다.
class Calculator:

    def __init__(self, n1, n2):
        print('[Calculator] __init__() called!!')
        self.num1 = n1
        self.num2 = n2

cal = Calculator(10, 20)
print(f'cal.num1: {cal.num1}')
print(f'cal.num2: {cal.num2}')

class Calculator:

    def __init__(self):
        print('[Calculator] __init__() called!!')
        self.num1 = 10
        self.num2 = 100

cal = Calculator() #매개변수의 값을 받지 않는 경우
print(f'cal.num1: {cal.num1}')
print(f'cal.num2: {cal.num2}')

class Calculator:

    def __init__(self, n1):
        print('[Calculator] __init__() called!!')
        self.num1 = n1
        self.num2 = 100

cal = Calculator(3.14) #매개변수의 값을 받지 않는 경우
print(f'cal.num1: {cal.num1}')
print(f'cal.num2: {cal.num2}')
  • super(): 상위 클래스의 속성을 초기화하기 위해서 사용한다.
  • 기능은 상속만 하면 바로 쓰일 수 있다.
  • 조건: 속성은 init 메서드가 호출되어야 속성을 초기화하여 사용할 수 있다!
class P_Class:

    def __init__(self, pNum1, pNum2):
        print('[P_Class} __init__() called!!')
        self.pNum1 = pNum1
        self.pNum2 = pNum2

class C_Class(P_Class): #상속!

    def __init__(self, cNum1, cNum2):
        print('[C_Class} __init__() called!!')

        # P_Class.__init__(self, cNum1, cNum2)
        super().__init__(cNum1, cNum2) #메서드를 호출하되, 값은 초기화해라

        self.cNum1 = cNum1
        self.cNum2 = cNum2

cls = C_Class(10, 20) #속성 초기화 하므로 C_Class만 호출

>>>
[C_Class} __init__() called!!
[P_Class} __init__() called!!
#실습하기1
#중간고사 클래스와 기말고사 클래스를 상속관계로 만들고 각각의 점수를 초기화하자.
#또한 총점 및 평균을 반환하는 기능도 만들어보자.

class MidExam:

    def __init__(self, s1, s2, s3):
        print('[MidExam] __init__()')

        self.mid_kor_score = s1
        self.mid_eng_score = s2
        self.mid_mat_score = s3

    def printScores(self):
        print(f'mid_kor_score: {self.mid_kor_score}')
        print(f'mid_eng_score: {self.mid_eng_score}')
        print(f'mid_mat_score: {self.mid_mat_score}')

class EndExam(MidExam):

    def __init__(self, s1, s2, s3, s4, s5, s6):
        print('[EndExam]__init__()')

        super().__init__(s1,s2,s3) #super를 할 때는 self 생략

        self.end_kor_score = s4
        self.end_eng_score = s5
        self.end_mat_score = s6

    def printScores(self): #상위 클래스
        super().printScores() #상위 클래스의 것은 알아서 출력
        print(f'end_kor_score: {self.end_kor_score}') #기말은 타이핑해서 출력
        print(f'end_eng_score: {self.end_eng_score}')
        print(f'end_mat_score: {self.end_mat_score}')

    def getTotalScore(self):
        total = self.mid_kor_score + self.mid_eng_score + self.mid_mat_score
        total += self.end_kor_score + self.end_eng_score + self.end_mat_score

        return total

    def getAverageScore(self):
        return self.getTotalScore() / 6


#
exam = EndExam(85, 90, 88, 75, 85, 95) #앞에가 중간 국영수, 뒤가 기말 국영수
exam.printScores()

print(f'Total: {exam.getTotalScore()}')
print(f'Average: {round(exam.getAverageScore(),2)}')

>>>
[EndExam]__init__()
[MidExam] __init__()
mid_kor_score: 85
mid_eng_score: 90
mid_mat_score: 88
end_kor_score: 75
end_eng_score: 85
end_mat_score: 95
Total: 518
Average: 86.33

25. 다중 상속

  • 다중 상속: 2개 이상의 클래스를 상속한다.
  • 주의할 점: 다중 상속을 남발하면 이름이 유사해서 헷갈릴 수 있기 떄문에 꼭 필요한 경우에만 사용하자!
class BasicCalculator:

    def add(self, n1, n2):
        return n1 + n2

    def sub(self, n1, n2):
        return n1 - n2

    def mul(self, n1, n2):
        return n1 * n2

    def div(self, n1, n2):
        return n1 / n2

class DeveloperCalculator:
    def mod(self, n1, n2):
        return n1 % n2

    def flo(self, n1, n2):
        return n1 // n2

    def exp(self, n1, n2):
        return n1 ** n2

class NewCalculator(BasicCalculator, DeveloperCalculator):
    def __init__(self):
        pass

cal = NewCalculator()

print(f'cal.add(10, 20): {cal.add(10, 20)}')
print(f'cal.sub(10, 20): {cal.sub(10, 20)}')
print(f'cal.mul(10, 20): {cal.mul(10, 20)}')
print(f'cal.div(10, 20): {cal.div(10, 20)}')


print(f'cal.mod(10, 20): {cal.mod(10, 20)}')
print(f'cal.flo(10, 20): {cal.flo(10, 20)}')
print(f'cal.exp(10, 20): {cal.exp(2, 5)}')

>>>
cal.add(10, 20): 30
cal.sub(10, 20): -10
cal.mul(10, 20): 200
cal.div(10, 20): 0.5
cal.mod(10, 20): 10
cal.flo(10, 20): 0
cal.exp(10, 20): 32

26. 오버라이딩

#실습하기2
#삼각형 넓이를 계산하는 클래스를 만들고 이를 상속하는 클래스에서 getArea()를 오버라이딩 해서
#출력 결과가 다음과 같을 수 있도록 클래스를 만들어보자.

class TriangleArea:

    def __init__(self, w, h):  #width, height
        self.width = w
        self.height = h

    def printTriangleAreaInfo(self):
        print(f'width: {self.width}')
        print(f'height: {self.height}')

    def getArea(self): #삼각형의 넓이
        return self.width * self.height / 2

class NewTriangleArea(TriangleArea):

    def __init__(self,w,h):
        super().__init__(w, h) #속성 초기화 #괄호 안에 self는 없음!!
    
    #재정의
    def getArea(self):
         return str(super().getArea()) + '㎠' #super로 올라가서 getArea에서 return 받은 값을 문자열로 변환 #중요!

ta = NewTriangleArea(7,5)
ta.printTriangleAreaInfo()
triangleArea = ta.getArea() #변수에 출력
print(f'triangleArea: {triangleArea}')

27. 추상 클래스

  • 추상 클래스: 상위 클래스에서 하위 클래스에 메서드 구현을 강요한다.
  • 구현을 하지 않으면 오류 발생
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('시속 400km/h 비행')

class fighterPlane(Airplane):

    def __init__(self, c):
        self.color = c

    def flight(self): ####각자 입맛에 따라 구현할 수 있음
        print('시속 700km/h 비행')

al = Airliner('red')
al.flight()
al.forward()
al.backward()

fl = fighterPlane('blue')
fl.flight()
fl.forward()
fl.backward()

>>>
시속 400km/h 비행
전진!!
후진!!
시속 700km/h 비행
전진!!
후진!!
#계산기 추상 클래스를 만들고 이를 이용해서 새로운 계산기 클래스를 만들어 보자.
#추상 클래스에는 덧셈, 뺄셈, 곱셈, 나눗셈 기능이 선언되어 있어야 한다.

from abc import ABCMeta ######
from abc import abstractmethod ######

class Calculator(metaclass=ABCMeta): ######

    @abstractmethod
    def add(self, n1, n2):
        pass

    @abstractmethod
    def sub(self, n1, n2):
        pass

    @abstractmethod
    def mul(self, n1, n2):
        pass

    @abstractmethod
    def div(self, n1, n2):
        pass

class DeveloperCalculator(Calculator):

    def add(self, n1, n2):
        print(n1 + n2)

    def sub(self, n1, n2):
        print(n1 - n2)

    def mul(self, n1, n2):
        print(n1 * n2)

    def div(self, n1, n2):
        print(n1 / n2)

    def mod(self, n1, n2): #나머지
        print(n1 % n2)

    def flo(self, n1, n2): #몫
        print(n1 // n2)

result = DeveloperCalculator() #지정된 것이 없음
result.add(10, 20)
result.sub(10, 20)
result.mul(10, 20)
result.div(10, 20)
result.mod(10, 20) #나머지
result.flo(10, 20) #몫

28. 예외란?

  • 예외란, 문법적인 문제는 없으나 실행 중 발생하는 예상하지 못한 문제이다.
    ex) 10 / 0 -> 어떤 수를 0으로 나눌 수는 없다.: zerodivisionerror

  • 에러: 천재지변 등 시스템 상으로 문제가 생기는 것

  • cf) 문법적 오류: syntax 에러

  • 예외 관련 클래스는 Exception 클래스를 상속한다.

  • 종류

  1. ZeroDivisionError
  2. IOError # 입출력과 관련된 에러
  3. IndexError #리스트에서 길이가 5인데, 인덱스 5를 찾았을 때: 길이가 5면 인덱스는 4까지!
  4. IndentationError #들여쓰기 에러
def add(n1, n2):
    print(n1+n2)

def div(n1, n2):
    print(n1/n2)

fn = int(input('input firstNum: '))
sn = int(input('input secondNum: '))

print(10/0) #0/10은 가능

add(fn, sn)
div(fn, sn)

#문자를 정수로 캐스팅할 수 없음
print(int('hello'))

lists = [1,2,3,4,5,6]
print(lists[6])

29. 예외 처리

  • 예외 처리: 발생된 예외를 별도 처리함으로써 프로그램 실행 시 문제가 없도록 한다.
  • 방법: 예외 발생 예상 구문을 try ~ except로 감싼다.
n1 = 10; n2 = 0

try:
    print(n1 / n2)
except:
    print('예상치 못한 문제가 발생했습니다!')
    print('다음 프로그램이 정상 실행됩니다.')

print(n1 * n2)
print(n1 - n2)
print(n1 + n2)
#실습하기1
#사용자로부터 숫자 5개를 입력받을 때 숫자가 아닌 자료형이 입력되면 예외 처리하는 프로그램을 만들어보자.

nums = []

n = 1
while n<6: #5번
    try:
        num = int(input('input number: ')) #문제가 발생할 수 있는 부분을 예외처리함 -> 정확하게 묶어줘야 함
    except:
        print('예외 발생!')
        continue #위로 올라가라

    nums.append(num) #nums라는 리스트에 num 값을 추가해준다.
    n += 1

print(f'nums: {nums}')

30. try ~ except ~ else

  • ~ else 구문: 예외가 발생하지 않은 경우 실행하는 구문이다.
  • else 구문은 생략이 가능하다.
  • else 구문은 try, except를 썼을 때만 사용할 수 있다.
nums = []

n = 1
while n < 6:
	try:
    	num = int(input('input number: ')) #예외
    except:
    	print('예외 발생!!')
        continue
    
    if num % 2 == 0: #짝수일 때
    	nums.append(num)
        n += 1
    else:
    	print('홀수 입니다 ', end='')
        print('다시 입력 하세요.')
        continue
 
 print(f'nums: {nums]')
#실습하기2
#사용자로부터 숫자 5개를 입력받아 짝수, 홀수, 실수로 구분해서 각각을 리스트에 저장하는 프로그램을 만들어보자.

eveList = []; oddList = []; floatList = []

n = 1
while n < 6:
	try:
    	num = float(input('input number: ')) #입력된 것이 문자일 때 예외처리
    except:
    	print('exception raise!!')
        print('input number again!')
        continue #위로 올려 보낸다.
    else:
    	
        if num - int(num) != 0: #실수일 때
        	print('float number!')
            floatList.append(num) #실수 일 때 추가
        else: #정수이자 짝수, 홀수일 때
        	if num % 2 == 0:
            	print('even number!')
                eveList.append(num)
            else:
            	print('odd number!')
                oddList.append(num)
        n += 1
        
print(f'eveList: {eveLists}')
print(f'oddList: {oddList}')
print(f'floatList: {floatList}')
        

31. finally

  • finally: 예외 발생과 상관없이 항상 실행한다. -> 예외가 발생하든, 안하든 이 문장은 꼭 실행하라.
#실습하기2
#사용자로부터 숫자 5개를 입력받아 짝수, 호룻, 실수와 입력한 모든 데이터를 각각 출력하는 프로그램을 만들어보자.

eveList = []; oddList = []; floatList = []
dataList = []

n = 1
# data = None  # data 변수를 초기화: name is not defined 오류 발생 시
while n < 6: #숫자 5개 입력

    try:
        data = input('input number: ')
        floatNum = float(data) #실수형으로 변환

    except:
        print('exception raise!!')
        print('input number again!!')
        continue

    else:

        if floatNum - int(floatNum) != 0: #실수
            print('float number!')
            floatList.append(floatNum)  # 실수형 리스트 안에 넣어준다.
        else:
            if floatNum % 2 == 0: #짝수
                print('even number!')
                eveList.append(int(floatNum)) #짝수, 홀수는 정수형으로 리스트 안에 넣어준다.
            else:
                print('odd number!')
                oddList.append(int(floatNum))

        n += 1

    finally: #try, except, else와 동일 선상에 있음 #에러가 나도 사용자가 입력한 것을 담아라
        dataList.append(data)


print(f'float: {floatList}')
print(f'even: {eveList}')
print(f'odd: {oddList}')
print(f'data: {dataList}')

32. Exception 클래스 / raise 키워드

  • Exception은 예외를 담당하는 클래스로, 어떤 예외가 발생했는지에 대한 정보를 알 수 있다.
num1 = int(input('input number1: '))
num2 = int(input('input number2: '))

try:
    print(f'num1 / num2 = {num1 / num2}')

except Exception as e: ##########
    print('0으로 나눌 수 없습니다.')
    print(f'exception: {e}')

print(f'num1 * num2 = {num1 * num2}')
print(f'num1 - num2 = {num1 - num2}')
print(f'num1 + num2 = {num1 + num2}')

>>>
input number1: 10
input number2: 0
0으로 나눌 수 없습니다.
exception: division by zero
num1 * num2 = 0
num1 - num2 = 10
num1 + num2 = 10
  • raise 키워드: 예외를 발생시킬 수 있다.
ef divCalculator(n1, n2):

    if n2 != 0:
        print(f'{n1} / {n2} = {n1 / n2}')

    else:
        raise Exception('0으로 나눌 수 없습니다.')

num1 = int(input('input numer1: '))
num2 = int(input('input numer2: '))

try:
    divCalculator(num1, num2) #오류 발생
except Exception as e: ########raise 키워드와 함께 들어감
    print(f'Exception: {e}')
#실습하기2
#사용자가 문자 메시지를 보낼 때 10글자 이하면 sms로 발송하고, 10글자를 초과하면 mms로 발송하는 프로그램을 예외 처리를 이용해서 만들어보자.

def sendSMS(msg):

    if len(msg) > 10:
        raise Exception('길이 초과!! MMS전환 후 발송!!', 1) #배열 형식: 앞에 값이 0이고 0부터 실행, 두 번째 값이 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: #두 번째 오는 게 1이라면
        sendMMS(msg) #실행시켜라
    elif e.args[1] == 2:
        sendSMS(msg)

33. 사용자 Exception 클래스

  • Exception 클래스를 상속해서 사용자 예외 클래스를 만들 수 있다.
class NotUseZeroException(Exception):

    def __init__(self, n):
        super().__init__(f'{n}은 사용할 수 없습니다!!')###########상위 클래스에 있는 init 메서드 호출

def divCalculator(num1, num2):

    if num2 == 0: #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: ###############NotUseException이 발생하면 내가 처리하겠다!
    print(e)
#실습하기2
#관리자 암호를 입력하고 다음 상태에 따라 예외 처리하는 예외 클래스를 만들어보자.
# 암호 길이가 5미만인 경우: PasswordLengthShortException
# 암호 길이가 10을 초과하는 경우: PasswordLengthLongException
# 암호가 잘못된 경우: PasswordWrongException

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}: 잘못된 비밀번호!!')

adminPw = input('input admin password: ')

try:
    if len(adminPw) < 5:
        raise PasswordLengthShortException(adminPw)
    elif len(adminPw) > 10:
        raise PasswordLengthLongException(adminPw)
    elif adminPw != 'admin1234':
        raise PasswordWrongException(adminPw)
    elif adminPw == 'admin1234':
        print('빙고!!')

except PasswordLengthShortException as e1:
    print(e1) # 프린트까지

except PasswordLengthLongException as e2:
    print(e2)

except PasswordWrongException as e3:
    print(e3)

34. 텍스트 파일 쓰기

  • 파이썬 파일이 아닌 외부 자원!
  • 기본 4가지 함수
    • open(): 파일 열기
    • read(): 읽기
    • write(): 쓰기
    • close(): 파일 닫기
  • 텍스트 파일 -> 1. open() -> 2.read() or write() -> 3.close()
#실습하기2
#다음과 같이 시스템 시간과 일정을 텍스트 파일에 작성해 보자.

#time 모듈 외우기!!!
import time
lt = time.localtime()
dateStr = '[' + str(lt.tm_year) + '년' + \
    str(lt.tm_mon) + '월' +\
    str(lt.tm_mday) + '일]'

todaySchedule = input('오늘 일정: ')

file = open('/Users/user1/Downloads/pythonEx/test.txt', 'w')
file.write(dateStr + todaySchedule) #txt 파일을 열었을 때 쓰여져 있음
file.close()

35. 텍스트 파일 읽기

#실습하기2
#다음 텍스트 파일에서 'Python'을 '파이썬'으로 변경해서 파일에 다시 저장해보자.

file = open('/Users/user1/Downloads/pythonEx/pythonTxt/about_python.txt', 'r')
# file = open('/Users/user1/Downloads/pythonEx/pythonTxt/about_python.txt', 'r', encoding='UTF8) #인코딩 문제 발생시

str = file.read()
print(f'str: {str}')

#변수 선언 필수!
str = str.replace('Python', '파이썬', 2) #앞에 나오는 2개만 바꾸겠다
print(f'str: {str}')
file.close()

str = str.replace('Python', '파이썬', 2) #앞에 나오는 2개만 바꾸겠다
print(f'str: {str}')

file = open('/Users/user1/Downloads/pythonEx/pythonTxt/about_python.txt', 'w')
file.write(str)
file.close()

36. 텍스트 파일 열기

  • 파일을 다양한 방식으로 open할 수 있다.
  • 파일 모드는 파일을 어떤 목적으로 open 할지 정한다.
    • 'w': 쓰기 전용(특징: 파일이 있으면 덮어씌움(기존에 있었던 내용은 삭제됨))
    • 'a': 쓰기 전용(파일이 있으면 덧붙임(기존에 있었던 내용 다음에 내용이 추가됨))
    • 'x': 쓰기 전용(기존 파일이 있으면 에러 발생)
    • 'r': 읽기 전용(파일이 없으면 에러 발생)
#'w' 파일 모드
file = open('/Users/user1/Downloads/pythonEx/pythonTxt/hello.txt', 'w')
file.write('Hello world!!')
file.close()

#'a' 파일 모드
file = open('/Users/user1/Downloads/pythonEx/pythonTxt/hello.txt', 'a')
file.write('\nNice to meet you!!')
file.close()

#'x' 파일 모드
file = open('/Users/user1/Downloads/pythonEx/pythonTxt/hello_01.txt', 'x')
file.write('\nNice to meet you!!')
file.close()

#'r' 파일 모드
file = open('/Users/user1/Downloads/pythonEx/pythonTxt/hello_01.txt', 'r')
str = file.read() #read가 있는 파일은 숫자여도 문자로 처리됨
print(f'str: {str}')
file.close()
#실습하기
#사용자가 입력한 숫자에 대한 소수를 구하고 이를 파일에 작성해보자.
def writePrimeNumber(n):
    file = open('/Users/user1/Downloads/pythonEx/pythonTxt/prime_numbers.txt', 'a') #기존에 있던 내용에서 덧붙임
    file.write(str(n)) #숫자로 바로 가면 에러가 나기 때문에 '문자'로 캐스팅을 해줘야 한다!!
    file.write('\n') #개행해라: 엔터처리
    file.close()

inputNumber = int(input('0보다 큰 정수 입력: '))
for number in range(2, (inputNumber+1)): #number가 내가 입력한 숫자 #사용자가 입력한 inputNumber까지
    flag = True
    for n in range(2, number):
        if number % n == 0: #나누어 떨어지면 소수가 아니다.
            flag = False
            break
    if flag: #flag = True #if (flag)
        writePrimeNumber(number)

37. with ~ as문

  • with ~ as문: 파일 닫기(close) 생략하기
with open('/Users/user1/Downloads/pythonEx/pythonTxt/5_037', 'a') as f:
    f.write('python study!!')

with open('/Users/user1/Downloads/pythonEx/pythonTxt/5_037', 'r') as f:
    print(f.read())
코드를 입력하세요
#실습하기2 => 복습하기
#로또 번호 생성기 프로그램을 만들고 파일에 번호를 출력해 보자.

import random
def writeNumbers(nums):
    for idx, num in enumerate(nums):
        with open('/Users/user1/Downloads/pythonEx/pythonTxt/lotto.txt', 'a') as f:
            if idx < (len(nums) - 2): #첫 번째부터 뒤에서 2번째 문자라면
                f.write(str(num) + ', ') #숫자를 바로 쓸 수는 없고 쓰려면 문자로 캐스팅 해주야 함
            elif idx == (len(nums) - 2): #뒤에서 두번째 문자라면
                f.write(str(num))
            elif idx == (len(nums) - 1):
                f.write('\n')
                f.write('bonus: ' + str(num)) #문자로 만들기
                f.write('\n')

rNums = random.sample(range(1, 46), 7) #로또에서는 1~45까지 랜덤한 7개의 숫자 추첨
print(f'rNums: {rNums}')

writeNumbers(rNums)

38. writelines()

  • writelines()는 리스트(List) 또는 튜플 데이터를 파일에 쓰기 위한 함수이다.
#실습하기2
#딕셔너리에 저장된 과목별 점수를 파일에 저장하는 코드를 작성하자.

scoreDic = {'kor': 85, 'eng': 90, 'mat': 92, 'sci': 79, 'his': 82}

for key in scoreDic.keys():
    with open('/Users/user1/Downloads/pythonEx/pythonTxt/scoreDic.txt', 'a') as f:
        f.write(key + '\t: ' + str(scoreDic[key]) + '\n') #scoreDic[key]의 키 값은 숫자기 때문
        
#파일을 그대로 열고 싶을 때
scoreDic = {'kor': 85, 'eng': 90, 'mat': 92, 'sci': 79, 'his': 82}
scoreList = [85, 90, 92, 79, 82] #'리스트'도 그래도 출력 가능!
with open('/Users/user1/Downloads/pythonEx/pythonTxt/scores.txt', 'a') as f:
    print(scoreDic, file=f) #이 파일을 실행하겠다!
    print(scoreList, file=f)
        

39. readlines(), readline()

  • readlines() : 파일의 모든 데이터를 읽어서 리스트 형태로 반환한다.
  • readline() : 한 행을 읽어서 문자열로 반환한다. -> 한 줄씩
#readlines() : 파일의 모든 데이터를 읽어서 리스트 형태로 반환한다.

languages = ['c/c++', 'java', 'c#', 'python', 'javascript']
with open('/Users/user1/Downloads/pythonEx/pythonTxt/languages.txt', 'r') as f:
    lanList = f.readlines()

print(f'lanList: {lanList}')
print(f'lanList type: {type(lanList)}')


#readline() : 한 행을 읽어서 문자열로 반환한다. -> 한 줄씩
with open('/Users/user1/Downloads/pythonEx/pythonTxt/languages.txt', 'r') as f:
    line = f.readline()

    while line != '': #비어있지 않다면 계속 읽어라
        print(f'line: {line}')
        line = f.readline()
#실습하기1
scoreDic = {} #비어있는 문자열 만들기
with open('/Users/user1/Downloads/pythonEx/pythonTxt/scores.txt', 'r') as f:
    line = f.readline()

    while line != '':
        tempList = line.split(':') ##split -> 구분자를 정해주면 분리해줌
        # print(f'tempList: {tempList}')
        scoreDic[tempList[0]] = int(tempList[1].strip('\n')) #키값 = 벨류값 ##strip: \n 값을 없애줌
        line = f.readline() #안적으면 무한으로 출력

print(f'scoreDic: {scoreDic}')
profile
데이터 분석 공부 기록

0개의 댓글