용어 정리 (출처- https://youtu.be/FRHGtAvU03Q?si=WU-AqPXehcSQOAe6)
클래스: 제품의 설계도
객체: 설계도로 만든 제품
속성: 클래스안의 변수
메서드: 클래스안의 함수
생성자: 객체를 만들 때 실행되는 함수
인스턴스: 메모리에 살아있는 객체
실습
속성이 색, 길이, 무게를 가진 5가지의 다른 비행기 객체 만들기
class Airplane:
def __init__(self, color, length, weight):
self.color = color
self.length = length
self.weight = weight
def take_off(self):
print('take_off')
def landing(self):
print('landing')
def print_plane_info(self):
print(f'flight\'s color is {self.color}')
print(f'flight\'s length is {self.length}')
print(f'flight\'s weight is {self.weight}')
plane1 = Airplane('red', 200, 400)
plane2 = Airplane('blue', 210, 433)
plane3 = Airplane('white', 260, 4600)
plane4 = Airplane('orange', 240, 490)
plane5 = Airplane('black', 230, 404)
plane1.print_plane_info()
plane2.print_plane_info()
plane3.print_plane_info()
plane4.print_plane_info()
plane5.print_plane_info()
변수는 객체의 메모리 주소를 저장하고 이를 이용해서 객체를 참조한다.
class Robot:
def __init__(self, color, height, weight):
self.color = color
self.height = height
self.weight = weight
def print_robot_infor(self):
print(f'color = {self.color}')
print(f'height = {self.height}')
print(f'weight = {self.weight}')
rb1 = Robot('red', 200, 88) #생성된 객체가 있는 메모리의 주소값이 rb1에 들어감
rb2 = Robot('blue', 230, 188)
rb3 = rb1 #rb3는 rb1이 가지고 있는 주소값이 카피된것. 즉, 하나의 객체를 공유
# rb1.print_robot_infor()
# rb2.print_robot_infor()
# rb3.print_robot_infor()
#속성 변경
rb1.color = 'gray'
rb1.height = 3000
rb1.weight = 300000
rb1.print_robot_infor()
rb2.print_robot_infor()
rb3.print_robot_infor() #rb1과 같은 값을 나타냄
얕은 복사란, 객체 주소를 복사하는 것으로 객체 자체가 복사되지 않는다.
class TemCls:
def __init__(self, n, s):
self.number = n
self.str = s
def print_cls_info(self):
print(f'self.number: {self.number}')
print(f'self.str: {self.str}')
#얕은 복사
tc1 = TemCls(10, 'hello')
tc2 = tc1
#
# tc1.print_cls_info()
# tc2.print_cls_info()
tc2.number = 22
tc2.str = 'ddd'
tc1.print_cls_info()
tc2.print_cls_info()
깊은 복사
깊은 복사란, 객체 자체를 복사하는 것으로 또 하나의 객체가 만들어진다.
#깊은 복사
import copy
tc1 = TemCls(10, 'hello')
tc2 = copy.copy(tc1)#레퍼런스가 갖고 있는 객체를 복사. 즉, tc1이랑은 아예 다른 객체가 됨
tc2.str = 'www'
tc2.number = 22
tc1.print_cls_info()
tc2.print_cls_info()#다른 속성을 가진 객체 정보가 출력
다양한 깊은 복사 방법
1. 반복문 이용하기
import copy
scores = [2,4,5,5,2,1,3]
scores_copy = []
for s in scores:
scores_copy.append(s)
print(f'id(scores): {id(scores)}')
print(f'id(scores_copy): {id(scores_copy)}') #서로 다른 값이 출력
scores_copy.extend(scores)
print(f'id(scores): {id(scores)}')
print(f'id(scores_copy): {id(scores_copy)}') #서로 다른 값이 출력
scores_copy = scores.copy()
print(f'id(scores): {id(scores)}')
print(f'id(scores_copy): {id(scores_copy)}') #서로 다른 값이 출력
scores_copy = scores[:]#리스트 슬라이싱
print(f'id(scores): {id(scores)}')
print(f'id(scores_copy): {id(scores_copy)}') #서로 다른 값이 출력
실습
선수의 원본 점수를 이용해서 평균을 출력하고, 최고값과 최저값을 제외한 평균을 출력하는 프로그램을 만들어보자.
player_original_score = [8.7, 9.1, 8.9, 9.0, 7.9, 9.5, 8.8, 8.3]
player_original_score.sort() #원본 점수 정렬
# print(player_original_score) #정렬 확인
copy_score = player_original_score.copy() #복사본 만들기
# print(copy_score) #복사본 확인
copy_score.sort() #복사본 정렬
# print(copy_score) #정렬 확인
del copy_score[0] #복사본의 최솟값 제거
del copy_score[-1] #복사본의 최댓값 제거
# print(copy_score) #제거 확인
print(f'player original score is: {player_original_score}')
print(f'player copy score is: {copy_score}')
original_total = round(sum(player_original_score),2) #원본 점수 총합 소수 둘 째자리까지 저장
original_avg = round(original_total/len(player_original_score),2) #원본 평균 점수 소수 둘 째자리까지 저장
print(f'original total score is {original_total}')
print(f'original avg score is {original_avg}')
copy_total = round(sum(copy_score),2) #복사본 점수 총합 소수 둘 째자리까지 저장
copy_avg = round(original_total/len(copy_score),2) #원본과의 평균 비교를 위해 원본의 총합/ 복사본의 수 (6)
print(f'copy total score is {copy_total}')
print(f'copy avg score is {copy_avg}')
print(f'original avg - copy avg is {original_avg - copy_avg}')
#결과
player original score is: [7.9, 8.3, 8.7, 8.8, 8.9, 9.0, 9.1, 9.5]
player copy score is: [8.3, 8.7, 8.8, 8.9, 9.0, 9.1]
original total score is 70.2
original avg score is 8.78
copy total score is 52.8
copy avg score is 11.7
original avg - copy avg is -2.92
클래스는 또 다른 클래스를 상속해서 내 것처럼 사용할 수 있다.
class Normal_car:
def drive(self):
print('{normal_car} drive() called!')
def back(self):
print('{normal_car] back() called!')
class Turbo_car(Normal_car): #Turbo_car 클래스가 Normal_car를 상속
def turbo(self):
print('{turbo_car} turbo() called!')
my_turbo_car = Turbo_car()
my_turbo_car.turbo()
#Turbo_car 클래스가 Normal_car를 상속했기 때문에 back과 drive 둘 다 사용 가능.
my_turbo_car.back()
my_turbo_car.drive()
실습
덧셈, 뺄셈 기능이 있는 클래스를 만들고, 이를 상속하는 클래스를 만들어서 곱셈과 나눗셈 기능을 추가해 보자.
class Calculator_super:
def add(self, n1, n2):
return n1 + n2
def sub(self, n1, n2):
return n1 - n2
class Caculator_child(Calculator_super):
def multi(self, n1, n2):
return n1 * n2
def div(self, n1, n2):
return n1 / n2
my_calculator = Caculator_child()
print(f'add: {my_calculator.add(10,20)}')
print(f'sub: {my_calculator.sub(10,20)}')
print(f'multiply: {my_calculator.multi(10,20)}')
print(f'divide: {my_calculator.div(10,20)}')
객체가 생성될 때 호출하면 __int__()가 자동으로 호출된다.
__int__()가 속성을 초기화 한다.
class Calculator():
def __init__(self, n1, n2):
print('[Calculator]__inti__() called!')
self.num1 = n1
self.num2 = n2
cal = Calculator(10,20) #속성 초기화
print(f'num1: {cal.num1}')
print(f'num2: {cal.num2}')
양식 업데이트를 위한 super():
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): #위 P_Class의 속성이 사라짐
print('[C_Class] __init__() called!')
super().__init__(cnum1,cnum2) #P_Class의 속성을 상속하기 위해선 super(). 사용. 즉, 그 전(P_Class)의 내용을 가져옴
self.cnum1 = cnum1
self.cnum2 = cnum2
cls = C_Class(10, 20)
print(f'cls.cNum1: {cls.cNum1}')
print(f'cls.cNum2: {cls.cNum2}')
print(f'cls.pNum1: {cls.pNum1}')
print(f'cls.pNum2: {cls.pNum2}')
실습
중간고사 클래스와 기말고사 클래스를 상속관계로 만들고 각각의 점수를 초기화하자. 또한 총점 및 평균을 반환하는 기능도 만들어보자.
class MidExam:
def __init__(self, s1, s2, s3):
print('[MidExam] __init__()')
self.mid_kor_score = s1
self.mid_eng_score = s2
self.mid_math_score = s3
def print_score(self):
print(f'mid_kor_score is {self.mid_kor_score}')
print(f'mid_eng_score is {self.mid_eng_score}')
print(f'mid_math_score is {self.mid_math_score}')
class FinalExam(MidExam):
def __init__(self, s1, s2, s3, s4, s5, s6):
super().__init__(s1, s2, s3)
self.final_kor_score = s4
self.final_eng_score = s5
self.final_math_score = s6
def print_score(self):
super().print_score()
print(f'final_kor_score is {self.final_kor_score}')
print(f'final_eng_score is {self.final_eng_score}')
print(f'final_math_score is {self.final_math_score}')
def get_total_score(self):
total = self.mid_kor_score + self.mid_eng_score + self.mid_math_score + self.final_math_score
total += self.final_kor_score + self.final_eng_score
return total
# return self.mid_kor_score + self.mid_eng_score + self.mid_math_score + \
# self.final_kor_score + self.final_eng_score + self.final_math_score
def get_avg(self):
return self.get_total_score()/6
exam = FinalExam(33, 55, 99, 44, 59, 88)
exam.print_score()
print(f'total score: {exam.get_total_score()}')
print(f'total score: {exam.get_avg()}')
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
my_car = Car()
my_car.drive()
my_car.fly()
my_car.turbo()
실습
BasicCalculator와 DeveloperCalculator 클래스를 다음과 같이 만들고 이들 클래스를 상속해서 Calculator 클래스를 만들고 사용해보자.
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 Caculator(BasicCalculator, DeveloperCalculator):
def __init__(self):
pass
cal = Caculator()
print(cal.flo(10, 20))
print(cal.add(10, 20))
print(cal.sub(10, 20))
print(cal.mul(10, 20))
print(cal.mod(10, 20))
print(cal.exp(10, 20))
하위 클래스에서 상위 클래스의 매서드를 재정의 한다.
class Robot:
def __init__(self, c, h, w):
self.color = c
self.height = h
self.weight = w
def fire(self):
print('미사일 발사!')
def print_Robot_info(self):
print(f'self.color = {self.color}')
print(f'self.height = {self.height}')
print(f'self.weight = {self.weight}')
class New_Robot(Robot):
def __init__(self, c, h, w):
super().__init__(c,h,w)
def fire(self): #fire 재정의 (override)
#super().fire()
print('레이저 발사')
my_robot.fire()
my_robot = New_Robot('red', 100, 200)
my_robot.print_Robot_info()
실습
삼각형 넓이를 계산하는 클래스를 만들고 이를 상속하는 클래스에서 get_triangle_area()를 오버라이딩 해서 출력 결과가 다음과 같을 수 있도록 클래스를 만들어보자.
class Triangle_Area:
def __init__(self, w, h):
self.width = w
self.height = h
def print_triangle_info(self):
print(f'triangle width : {self.width}')
print(f'triangle height : {self.height}')
def get_traingle_area(self):
return self.width * self.height/ 2
class New_Triangle_Area(Triangle_Area):
def __init__(self, w, h):
super().__init__(w,h)
def get_traingle_area(self):
return str(super().get_traingle_area()) + '㎠'
ta = New_Triangle_Area(20, 4)
ta.print_triangle_info()
ta_area = ta.get_traingle_area()
print(f'area: {ta_area}')
상위 클래스에서 하위 클래으세 메서드 구현을 강요한다.
from abc import ABCMeta
from abc import abstractmethod
class AirPlane(metaclass=ABCMeta):
@abstractmethod #강제로 구현해야 되는 메소드 위에 붙여줌줌
def flight(self): #AirPlane을 상속하기 위해서는 이 부분을 구현해서 써야됨
pass
def forward(self):
print('전진!')
def backward(self):
print('후진!')
class Airliner(AirPlane):
def __init__(self, c):
self.color = c
def flight(self):
print('시속 300km/h 비행')
al = Airliner('White')
al.forward()
al.backward()
al.flight()
실습
계산기 추상 클래스를 만들고 이를 이용해서 새로운 계산기 클래스를 만들어보자. 추상 클래스에는 덧셈, 뺄셈, 곱셈, 나눗셈 기능이 선언되어 있어야 한다.
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 multi(self, n1, n2):
pass
@abstractmethod
def div(self,n1,n2):
pass
class DevelopCalculator(Calculator):
def add(self,n1,n2):
print(n1 + n2)
def sub(self,n1,n2):
print(n1 - n2)
def multi(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)
cal = DevelopCalculator()
cal.flo(10,20)
cal.mod(10,20)
cal.div(10,20)
cal.sub(10,20)
cal.multi(10,20)
cal.add(10,20)
예외란, 문법적인 문제는 없으나 실행 중 발생하는 예상하지 못한 문제이다.
ex) 어떤 수를 0으로 나눈 경우
발생된 예외를 별도 처리함으로써 프로그램 전체의 실행에 문제가 없도록 함.
예외 발생 예상 구문을 try~except로 감싼다.
n1 = 10; n2 = 0
try:
print(n1/n2)
except:
print('예상치 못한 예외가 발생했습니다.')
print('다른 프로그램 실행에는 문제 없습니다.')
print(n1 * n2)
print(n1 - n2)
print(n1 + n2)
실습
사용자로부터 숫자 5개를 입력 받을 때 숫자가 아닌 자료형이 입력되면 예외 처리하는 프로그램을 만들어보자.
nums = []
n = 1
while n < 6:
try:
num = int(input('숫자 입력: '))
except:
print('예외발생!')
continue
nums.append(num)
n += 1
print(nums)
예외가 발생하지 않았을 때 실행하는 구문 (try~except~else)
else는 try, except를 사용한 후에만 사용할 수 있다.
nums = []
n =1
while n < 6:
try:
num = int(input('input number: '))
except:
print('please type number.')
continue
else:
if num % 2 == 0:
nums.append(num)
n += 1
else:
print('The number you typed is odd number.', end = '')
print('please type the numebr agian')
continue
print(f'nums = {nums}')
실습
사용자로부터 숫자 5개를 입력받아 짝수, 홀수, 실수로 구분해서 각각을 리스트에 저장하는 프로그램을 만들어보자.
even_list = []; odd_list=[]; float_list = []
n = 1
while n <6:
try:
number = float(input('type number: '))
n += 1
except:
print('please type number')
continue
else:
if number - int(number) != 0:
print('it is a float number')
float_list.append(number)
elif number % 2 == 0:
print('its an even number')
even_list.append(int(number))
else:
print('it is an odd number')
odd_list.append(int(number))
print(f'float list = {float_list}')
print(f'even list = {even_list}')
print(f'odd list = {odd_list}')
Finally - 예외 발생과 상관없이 항상 실행한다.
try:
input_Data = input('input number: ')
num_int = int(input_Data)
except:
print('plase tpye a number')
else:
if num_int % 2 == 0:
print('its an even number')
else:
print('its an odd number')
finally:
print(f'input data: {input_Data}')
Exception 클래스
num1 = int(input('input num1: '))
num2 = int(input('input num2: '))
try:
print(f'num1 / num2 = {num1/num2}')
except Exception as e:
print(f'exepction: {e}') # print: exepction: division by zero
print(f'num1 + num2 = {num1 + num2}')
print(f'num1 - num2 = {num1 - num2}')
print(f'num1 * num2 = {num1 * num2}')
raise
raise 키워드를 이용하면 예외를 발생시킬 수 있다.
def div_calculation(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:
div_calculation(num1, num2)
except Exception as e:
print(f'Exception: {e}')
실습
사용자가 문자 메세지를 보낼 때 10글자 이하면 SMS로 발송하고, 10글자를 초과하면 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)
elif e.args[1] == 2:
sendSMS(msg)
Exception 클래스를 상속해서 사용자 예외 클래스를 만들 수 있다.
실습
관리자 암호를 입력하고 다음 상태에 따라 예외 처리하는 예외 클래스를 만들어보자.
class PasswordLengthShortExeption(Exception):
def __init__(self,str):
super().__init__(f'{str}: 길이 5 미만')
class PasswordLengthLongExeption(Exception):
def __init__(self,str):
super().__init__(f'{str}: 길이 10 초과')
class PasswordLengthWrongExeption(Exception):
def __init__(self,str):
super().__init__(f'{str}: 잘못된 비밀번호')
adminPw = input('password: ')
try:
if len(adminPw) < 5:
raise PasswordLengthShortExeption(adminPw)
elif len(adminPw) > 10:
raise PasswordLengthLongExeption(adminPw)
elif adminPw != 'admin1234':
raise PasswordLengthWrongExeption(adminPw)
elif adminPw == 'admin1234':
print('bingo!')
except PasswordLengthShortExeption as e1:
print(e1)
except PasswordLengthLongExeption as e2:
print(e2)
except PasswordLengthWrongExeption as e3:
print(e3)
file = open('C:/pythonTxt/test.txt','w') #/test.txt 파일 생성/ ,'w' -> 쓰기모드
strCnt = file.write(dateStr + todaySchedule)
print(f'strCnt: {strCnt}')
file.close()
#예시 1
file = open('C:/pythonTxt/test.txt','r')
str = file.read()
print(f'str: {str}')
file.close()
예시 2
file = open('C:/pythonTxt/about_python.txt', 'r', encoding= 'UTF8')
str = file.read()
print(f'str: {str}')
file.close()
str = str.replace('Python', '파이썬', 2) #2개의 Python 문자를 파이썬으로 바꿈
print(f'str: {str}')
with open('C:/pythonTxt/about_python.txt', 'w', encoding='utf-8') as f:
f.write(str)
f.close()
#'w': 쓰기 전용 (파일이 있으면 덮어씌움)
url = 'C:/pythonTxt/'
file = open(url + 'hello.txt', 'w')
file.write('HELLO PYTHON')
file.close()
#'a': 쓰기 전용 (파일이 있으면 덧붙임)
url = 'C:/pythonTxt/'
file = open(url + 'hello.txt', 'a')
file.write('\nnice to meet you')
file.close()
#'x': 쓰기 전용 (파일이 있으면 에러 발생)
url = 'C:/pythonTxt/'
file = open(url + 'hello.txt', 'x')
file.write('\nnice to meet you')
file.close()
#'r': 읽기 전용 (파일이 없으면 에러 발생)
url = 'C:/pythonTxt/'
file = open(url + 'hello.txt', 'r')
str = file.read()
print(str)
file.close()
실습
사용자가 입력한 숫자에 대한 소수를 구하고 이를 파일에 작성해보자
url = 'C:/pythonTxt/'
def write_prime_numers(n):
file = open(url + 'prime_numbers.txt', 'a')
file.write(str(n))
file.write('\n')
file.close()
input_number = int(input('0보다 큰 정수 입력: '))
for number in range(2,input_number + 1):
flag = True
for n in range(2, number + 1):
if number % n == 0:
flag = False
break
if flag:
write_prime_numers(number)
#읽기
with open(url + '5_036.txt', 'a') as f:
f.write('python study!')
#쓰기
with open(url + '5_036.txt', 'r') as f:
print(f.read())
실습
로또 번호 생성기 프로그램을 만들고 파일에 번호를 출력해보자
import random
url = 'C:/pythonTxt/'
def write_numbers(nums):
for idx, num in enumerate(nums):
with open(url + 'lotto_num.txt', 'a') as f:
if idx < len(nums) -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))
rNums = random.sample(range(1,46),7)
print(f'rNums: {rNums}')
write_numbers(rNums)
writelines()는 리스트 또는 튜플 데이터를 파일에 쓰기 위한 함수이다.
languages = ['c++', 'java', 'c#', 'python']
url = 'C:/pythonTxt/'
with open(url + 'languages.txt', 'a') as f:
f.writelines(languages)
#f.writelines(item + '\n' for item in languages) 아이템 하나씩 개행하려면 이렇게
실습
딕셔너리에 저장된 과목별 점수를 파일에 저장하는 코드를 작성하자.
url = 'C:/pythonTxt/'
#특정한 포멧으로 만들고 싶을 때
scoreDic = {'kor': 85, 'eng': 95, 'math': 85, 'sci': 95, 'his': 35}
for key in scoreDic.keys():
with open(url + 'score_dic.txt', 'a') as f:
f.write(key + '\t:' + str(scoreDic[key]) + '\n')
scoreDic = {'kor': 85, 'eng': 95, 'math': 85, 'sci': 95, 'his': 35}
with open(url + 'scores.txt', 'a') as f:
print(scoreDic, file= f) #딕셔너리나 리스트 자체를 저장하고 싶을 때
파일의 모든 데이터를 읽어서 리스트 형태로 변환한다.
url = 'C:/pythonTxt/'
with open(url + 'lans.txt', 'r') as f:
lanList = f.readlines()
한 행을 읽어서 문자열로 반환한다.
with open(url + 'lans.txt', 'r') as f:
line = f.readline()
while line != ''
print(f'line: {line}', end = '')
line = f.readline()
실습
파일에 저장된 과목별 점수를 파이썬에서 읽어, 딕셔너리에 저장하는 코드를 만들어보자.
scoreDic = {}
with open(url + 'scores.txt', 'r') as f:
line = f.readline()
while line != '':
templist = line.split(':') #()것을 기준으로 (구분자) 해서 다 리스트로 분리해줌.
scoreDic[templist[0]] = int(templist[1].strip('\n')) #\n 문자 삭제
line = f.readline()
print(f'scoredic: {scoreDic}')