객체지향프로그래밍

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

  • 객체 만들기(생성)

  • 객체 사용의 장점


클래스와 객체 생성

  • 클래스는 class 키워드와 속성(변수) 그리고 기능(함수)를 이용해서 만든다.
class Car: # 첫글자는 대문자로 입력한다.

    def __init__(self, col, len):
        self.color = col
        self.length = len

    def doStop(self):
        print('STOP!!')

    def doStart(self):
        print('START!!')

    def printCalInfo(self):
        print(f'self.color : {self.color}')
        print(f'self.length : {self.length}')

cal1 = Car('red',200)
cal2 = Car('blue',300)

cal1.printCalInfo()
cal2.printCalInfo()

객체 속성 변경

  • 객체속성은 변경할 수 있다.
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
result = cal.add()
print(f'result : {result}')
result = cal.sub()
print(f'result : {result}')
result = cal.mul()
print(f'result : {result}')
result = cal.div()
print(f'result : {result}')

객체와 메모리

  • 변수는 객체의 메모리 주소를 저장하고 이를 이용해서 객체를 참조한다.
    • 객체는 클래스로부터 생성자를 호출해서 메모리에 생성됨.
    • 메모리에 생성된 객체를 사용하기위해서 변수를 만들어 변수에 객체를 할당해서 사용
    • 객체가 생성될때 생성되는 메모리 주소를 변수에 저장이되어 변수로 객체를 불러올수있다.
    • 주소값을 가지고 객체를 참조한다고해서 래퍼런스 변수라고도함.
class Robot:
    def __init__(self, color, height, weight):
        self.color = color
        self.height = height
        self.weight = weight

    def printRobotInfo(self):
        print(f'color : {self.color}')
        print(f'height : {self.height}')
        print(f'weight : {self.weight}')

rb1 = Robot('red', 200, 80) # rb1이라는 변수를 이용하여 객체를 불러온다. rb1이라는 주소에서 printRobotInfo()함수를 불러와서 실행이된다.
rb2 = Robot('blue', 300, 120)
rb3 = rb1 # rb3에다가 rb1의 주소값이 복사된다(객체가 복사되는게아닌 객체가 가지고있는 주소값이 복사된다.)

rb1.printRobotInfo()
rb2.printRobotInfo()
rb3.printRobotInfo()

rb1.color = 'gray'
rb1.height = 250
rb1.weight = 100

rb1.printRobotInfo()
rb2.printRobotInfo()
rb3.printRobotInfo()
scores = [int(input('국어 점수 입력 : ')),
          int(input('영어 점수 입력 : ')),
          int(input('수학 점수 입력 : '))]

print(scores)

copyScores = scores.copy() # copy()를 이용하여 새로운 객체로 복사할수있다.
# 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)}')
print(copyScores)

객체 복사에 대한 이해

얕은 복사

  • 얕은 복사란, 객체 주소를 복사하는 것으로 객체 자체가 복사되지 않는다.
    • 얕은 복사란 메모리의 주소를 복사하여 같은 객체가 같은 메모리에 저장된 데이터를 가리키는걸 뜻한다.
class TemCls:

    def __init__(self, n, s):
        self.number = n
        self.str = s

    def printClsInfo(self):
        print(f'self.number = {self.number}')
        print(f'self.str = {self.str}')

tc1 = TemCls(10, 'hello')
tc2 = tc1 # 얕은 복사로 tc1을 tc2로 복사하였다.
tc1.printClsInfo()
tc2.printClsInfo()

tc2.number = 3.14 # 복사한 tc2로 인수를 변경하였지만 tc1과 tc2는 같은 주소로 
# 같은 메모리를 가리키고있기 때문에 출력하였을때 같은 데이터가 출력된다.
tc2.str = 'Bye'

tc1.printClsInfo()
tc2.printClsInfo()

출력후 결과

깊은 복사

  • 깊은 복사란, 객체 자체를 복사하는 것으로 또 하나의 객체가 만들어진다.
# 깊은 복사
class TemCls:

    def __init__(self, n, s):
        self.number = n
        self.str = s

    def printClsInfo(self):
        print(f'self.number = {self.number}')
        print(f'self.str = {self.str}')

import copy # copy를 이용하여 깊은 복사를 할수 있다.
tc1 = TemCls(10, 'Hello')
tc2 = copy.copy(tc1) # 메모리자체를 복사하여 서로다른 주소를 갖게되어 
# tc2의 데이터를 변경하여도 tc1은 그대로 유지되는것을 확인할 수 있다.

tc1.printClsInfo()
tc2.printClsInfo()
print('-'*25)
tc2.number = 3.14
tc2.str = 'Bye'
tc1.printClsInfo()
tc2.printClsInfo()


클래스 상속

  • 다른 클래스의 기능을 내 것처럼 사용하자!
# 상속 예시
class NormalCar:

    def drive(self):
        print('[NormalCar] drive() called!!')

    def back(self):
        print('[NormalCar] back() called!!')

class TurboCar(NormalCar): # NormalCar클래스를 상속받아 사용할수 있다.

    def turbo(self):
        print('[NormalCar] turbo() called!!')

myTurboCar = TurboCar()

myTurboCar.turbo() 
myTurboCar.drive()
myTurboCar.back()
# 상속받은 상태여서 NormalCar클래스의 함수들도 출력이되는걸 확인할수 있다.


생성자

class Calculator:

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

Calculator()

생성자만 호출하면 init이 호출되는 것을 확인 할 수 있다.

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):
        print('[C_Class] __init__() called!!')

        #P_Class.__init__(self, cNum1, cnum2) # 방법 1
        super().__init__(cNum1, cnum2) # 방법 2

        self.cNum1 = cNum1
        self.cnum2 = cnum2

cls = C_Class(10, 20)


다중상속

  • 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 Cal(Car01, Car02, Car03): # 다중상속하여 Car01 ~ Car03까지 클래스를 사용할수 있다.
    def __init__(self):
        pass

myCal = Cal()
myCal.drive()
myCal.turbo()
myCal.fly()


오버라이딩

  • 하위 클래스에서 상위 클래스의 메서드를 재정의(override) 한다.
class TriangleArea:
    def __init__(self, w, h):
        self.width = w
        self.height = h

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

    def getArea(self):
        return self.width * self.height / 2

class NewTriangleArea(TriangleArea):
    def __init__(self, w, h):
        super().__init__(w, h)

    def getArea(self):
        return str(super().getArea()) + '㎠'

ta = NewTriangleArea(7, 5)
ta.printTriangleAreaInfo()
triangleArea = ta.getArea()
print(f'triangleArea : {triangleArea}')
# 오버라이딩으로 계산된 데이터를 str로 변환하여 문자열을 붙여서 출력(17.5㎠)

추상클래스

  • 상위 클래스에서 하위 클래스에 메서드 구현을 강요한다.

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()
print('-'*25)
al = fighterPlane('red')
al.flight()
al.forward()
al.backward()


예외란?

  • 문법적인 문제는 없으나 실행 중 발생하는 예상하지 못한 문제이다.
    예외와 에러는 다르다.

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

예외처리

  • 예상하지 못한 예외가 프로그램 전체 실행에 영향이 없도록 처리함.
    • 프로그램실행순서에서 중간단계에서 예외처리가 발생했을경우 발생한 예외처리만 별도 처리하고 실행순서에 영향이 안가게 처리해주는 방법

try ~ except

  • 예외 발생 예상 구문을 try ~ except로 감싼다.
n1 = 10; n2 = 0

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

print(n1 * n2)
print(n1 - n2)
print(n1 + n2)

n2 변수에 0이 들어있어 예외가 발생하지만 try ~ except구문으로 처리한 예시

try ~ except ~ else

  • else : 예외가 발생하지 않은 경우 실행하는 구문이다.
nums = []
n = 1
while n < 6:
    try:
        num = int(input('input number : '))
    except:
        print('예외 발생!!')
        continue
    else:
        if num % 2 == 0:
            nums.append(num)
            n += 1
        else:
            print('홀수 입니다.', end='')
            print('다시 입력 하세요.')
            continue

print(f'nums : {nums}')


finally

  • 예외 발생과 상관없이 항상 실행한다.
evenList = []; oddList = []; floatList = []; dataList = []
n = 1
while n < 6:
    try:
        data = input('input number : ')
        floatNum = float(data)
    except:
        print('exception raise!!')
        print('not number!!')
        continue
    else:
        if floatNum - int(floatNum) != 0:
            print('float number!!')
            floatList.append(floatNum)
        else:
            if floatNum % 2 == 0:
                print('even number!!')
                evenList.append(floatNum)
            else:
                print('odd number!!')
                oddList.append(floatNum)
        n += 1
    finally:
        dataList.append(data)

print(f'evenList : {evenList}')
print(f'oddList : {oddList}')
print(f'floatList : {floatList}')
print(f'dataList : {dataList}')


Exception 클래스

  • Exception은 예외를 담당하는 클래스이다.

  • raise 키워드를 이용하면 예외를 발생시킬 수 있다.

사용자 예외클래스

  • Exception 클래스를 상속해서 사용자 예외 클래스를 만들 수 있다.
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)


텍스트

텍스트파일 쓰기

import time

lt = time.localtime()

dataStr = '[' + str(lt.tm_year) + '년 ' + \
          str(lt.tm_mon) + '월 ' + str(lt.tm_mday) + '일] '

todaySchedule = input('오늘 일정 : ')
file = open('C:/PythonTxt/test.txt', 'w')
file.write(dataStr + todaySchedule)
file.close()

코드 실행결과 텍스트파일인 메모장에 입력되는것을 확인할 수 있다.


텍스트파일 읽기

file = open('C:/PythonTxt/test.txt','r')

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


텍스트파일 열기 모드

open('파일의 경로를 입력하면된다.','w') - 쓰기전용
open('파일의 경로를 입력하면된다.','a') - 쓰기전용
open('파일의 경로를 입력하면된다.','x') - 쓰기전용
open('파일의 경로를 입력하면된다.','r') - 읽기전용

with ~ as문

with open(uri + '5_037.txt', 'a') as f:
    f.write('python study!!')

with open(uri + '5_037.txt', 'r') as f:
    print(f.read())


writelines()

languages = ['c/c++', 'java', 'c#', 'python', 'javascript']

uri = 'C:/PythonTxt/'
# 리스트를 파일에 쓸수있는 1번째 방법
for item in languages:
    with open(uri + 'languages.txt', 'a') as f:
        f.write(item)
        f.write('\n')
# 리스트를 파일에 쓸수있는 2번째 방법    
with open(uri + 'languages.txt', 'a') as f:
    f.writelines(item + '\n' for item in languages)

uri = 'C:/PythonTxt/'
# 딕셔너리를 하나씩 입력하는 방법
scoreDic = {'kor':85, 'eng':90, 'mat':92, 'sci':79, 'his':82}
for key in scoreDic.keys():
    with open(uri+'scoreDic.txt', 'a') as f:
        f.write(key + '\t: ' + str(scoreDic[key]) + '\n')
# 딕셔너리 자체를 한번에 입력하는 방법
scoreDic = {'kor':85, 'eng':90, 'mat':92, 'sci':79, 'his':82}
with open(uri+'scores.txt', 'a') as f:
    print(scoreDic, file=f)

readlines()

모든 데이터를 읽어오다보니 \n까지 출력되는걸 확인할수 있다.

readline()

uri = 'C:/PythonTxt/'

with open(uri + 'lans.txt','r') as f:
    lanList = f.readlines()

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

print('-'*25)

with open(uri + 'lans.txt','r') as f:
    line = f.readline()
    while line != '':
        print(f'line : {line}', end='')
        line = f.readline()

profile
코딩공부중

0개의 댓글