1. 모듈

1) 모듈 사용

  1. import 키워드 이용해서 모듈을 임포트 한다.
    • import calculator as cal
      --> calculator라는 모듈을 improt하고 cal 로 단축해서 사용하겠다.
  2. from ~ as 키워드 이용해 모듈의 특정 기능만 사용 가능
    • from calculator import add
      --> calculator 모듈에서 add() 기능만 사용하겠다.
    • from calculator import add,sub,mul
      --> calculator 모듈에서 add(),sub(),mul()기능을 사용하겠다.
    • from calculator import *
      -->calculator모듈에 모든 기능을 사용하겠다 == claculator모듈 import

2) 자주 사용하는 모듈 및 함수

- 수학관련 내부함수

#합
lisrVar = [2, 5, 3.14, 58, 10, 2]
print(f'{sum(lisrVar)}')

#최댓값
lisrVar = [2, 5, 3.14, 58, 10, 2]
print(f'{max(lisrVar)}')

#최솟값
lisrVar = [2, 5, 3.14, 58, 10, 2]
print(f'{min(lisrVar)}')

#거듭제곱
print(f'{pow(12,2)}')

#반올림
print(f'{round(3.141592,1)}')

- math 모듈

import math

#절대값
print(f'{math.fabs(-10)}')
print(f'{math.fabs(-0.20314)}')

#올림
print(f'{math.ceil(5.21)}')

#내림
print(f'{math.floor(5.21)}')

#버림
print(f'{math.trunc(5.32)}')

#최대공약수
print(f'{math.gcd(12,24)}')

#팩토리얼
print(f'{math.factorial(10)}')

#제곱근
print(f'{math.sqrt(4)}')

- time 모듈

import time

lt = time.localtime()

#현제 년월일 시간 정보
print(f'{lt}')

#현제 연도
print(f'{lt.tm_year}')
#현제 월
print(f'{lt.tm_mon}')
#현제 일
print(f'{lt.tm_mday}')
#현제 시,분,초
print(f'{lt.tm_hour}')
print(f'{lt.tm_min}')
print(f'{lt.tm_sec}')
#현제 요일
print(f'{lt.tm_wday}')
#결과 2 이면 수요일(0부터 월요일)

2. 실행(메인) 파일

1)--name--

  • 파이썬에서 기본적으로 제공하는 전역변수
  • 모듈명이 저장되거나 --main--이 저장된다.
  • --main--이 저장되는 이유는 실행파일(메인)을 모듈과 구분짓기 위해서이다.

예제1) 길이(cm)를 입력받아 mm, inch, m, feet로 환산하는 모듈을 만들어보자

1.환산해주는 기능을 가진 모듈 제작

2.실행 파일

  • 결과

3. 패키지

  • 디렉토리와 동일
  • 모듈을 모아두고 효율적으로 관리 할 수 있는 것
  • 똑같은 이름의 모듈인데 기능이 다르다면 각각 다른 패키지에 넣어 구분짓기

1)범용패키지(site-package)

  1. 모듈제작을 해도 동일 패키지 안에서만 제작한 모듈을 사용 할 수 있다.
  2. 제작한 모듈을 다른 패키지에서도 자유롭게 사용하기 위해 site-package로 해당 모듈이 있는 패키지를 옮긴다.
  3. 프로젝트 내에서 언제나 사용 가능

site - package 위치

venv - Lib - site-package

  • 이 위치에 해당 패키지를 잘라 붙여넣으면 해당 프로젝트내에서 어디서든 해당 패키지에 속한 모듈기능 사용 가능

⭐4. 객체지향⭐

객체를 이용한 프로그램으로 객체는 속성,기능 으로 구성

1) 객체지향 의미 이해

  • 객체(Object) = 속성(Attribute) + 기능(Function)
  • 일상생활 속으로 생각해보면
    • 자동차(객체)
      -- 속성 : 색상,가격,크기...
      -- 기능 : 전진, 후진, 정지...
    • 계산기(객체)
      -- 속성 : 숫자
      -- 기능 : 덧셈, 뺄셈, ...

객체지향 프로그램 : 일상생활에서의 객체 의미를 프로그램에 가져와서 프로그램을 구현 한 것

2) 객체 생성

3) 장점

  • 코드 재사용, 모듈화에 좋다.
  • 결합도가 낮아 조립하는 식으로 프로그래밍 가능

4) 클래스 만들기

  • 객체를 생성하기 위해서는 클래스는 먼저 생성해야 한다.
  • 클래스명의 첫 글자는 대문자로 한다.

5) 객체 생성

  • 클래스 = 붕어빵 틀, 객체 = 붕어빵

예제1) 비행기 클래스를 만들고 비행기 객체 생성해보자

#클래스 생성
class Airplain:
    #속성 정의
    def __init__(self,siz,spd):
        self.size = siz
        self.speed = spd
    #기능 정의
    def doFly(self):
        print('날아라')

    def doLend(self):
        print('착륙하라')

    def printInfo(self):
        print(f'size = {self.size}')
        print(f'speed = {self.speed}')

#Airplane클래스 생성자 호출
air1 = Airplain(2000,500.34)
air2 = Airplain(4945,690)

air1.doFly()
air2.doLend()
air1.printInfo()
날아라
착륙하라
size = 2000
speed = 500.0

6) 객체의 속성 변경

객체의 속성은 변경이 가능하다.

#클래스 생성
class NewGenerationPC:
    def __init__(self, name, cpu, memory, ssd):
        #self.name의 name은 NewGeneration의 객체에 속해있는 속성, 매개변수에서 받은 name
        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'name : {self.name}')
        print(f'cpu : {self.cpu}')
        print(f'memory : {self.memory}')
        print(f'ssd : {self.ssd}')

#생성자 호출
myPC1 = NewGenerationPC('김준호', 'i7','16G','256G')
myPC1.printPCInfo()

friendPC1 = NewGenerationPC('rlatl', 'i3','8G','32G')
friendPC1.printPCInfo()

#객체 속성 변경
myPC1.cpu = 'i9'
myPC1.memory = '64G'
myPC1.ssd = '1T'

#변경된 속성 적용되어 출력
myPC1.printPCInfo()
name : 김준호
cpu : i7
memory : 16G
ssd : 256G
------------
name : rlatl
cpu : i3
memory : 8G
ssd : 32G
------------
name : 김준호
cpu : i9
memory : 64G
ssd : 1T

7) 객체와 메모리 (참조변수)

  • 객체를 사용하기 위해서 변수를 만들었다.
    myCar = Car('red',200)
  • 변수(myCar)는 객체(Car())와 메모리 내에 각각 다른 위치에 저장되어 있다.
  • 즉, 변수에 직접 객체가 저장되는게 아니다.
  • 객체가 생성 될 때 메모리 주소가 생성된다. 이 메모리 주소가 변수에 저장이 된다.
  • 따라서, 변수를 이용해서 객체를 조작한건 정확히는 변수 안의 객체의 메모리주소를 이용해 조작했던 것
  • 이런 변수를 [참조변수] 라고한다.

예제1)

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객체가 들어있는게 아니라 rb1이 객체주소를 참조하는 것이다.
rb1 = Robot('red',200,80)
rb2 = Robot('blue',300,120)

# 이렇게 복사를 한다면 rb1이 참조하고 있는 객체주소가 rb3에 저장되는 것
#따라서 rb3이랑 rb1은 같은 객체
rb3 = rb1

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

#rb1객체 속성을 변경하면 rb3의 속성도 변경된다. 같은 객체주소를 참조하고 있으니까
rb1.color = 'gray'
rb1.height = 199
rb1.weight = 200

rb1.printRobotInfo()
rb2.printRobotInfo()
rb3.printRobotInfo()
Color :red
height :200
weight :80

Color :blue
height :300
weight :120

Color :red
height :200
weight :80
--------------------
Color :gray
height :199
weight :200

Color :blue
height :300
weight :120

Color :gray
height :199
weight :200
--------------------

8) 얕은 복사, 깊은 복사

  • 얕은 복사 : [객체 주소]를 복사하는 것으로 객체 자체가 복사 되지는 않는다.
  • 깊은 복사 : [객체] 자체를 복사하는 것으로 또 하나의 객체가 만들어 진다.

예시1.

class TemCls:
    def __init__(self,n, s):
        self.number = n
        self.string = s
    def printClsInfo(self):
        print(f'number = {self.number}')
        print(f'string = {self.string}')
  • 얕은 복사
#얕은 복사
tc1 = TemCls(100,'hello')
tc2 = tc1

tc1.printClsInfo()
tc2.printClsInfo()
print(id(tc1))
print(id(tc2))
print('-'*15)

tc2.num = 3.14
tc1.printClsInfo()
tc2.printClsInfo()

<#id(): 주소를 읽을  있다.>
print(id(tc1))
print(id(tc2))
print('-'*15)
  • tc2 = tc1 이렇게 복사를 하면 객체주소가 복사가 되어 참조하는 주소가 똑같다
    • id()로 어떤 주소를 참조하는지 알아볼 수 있다. (tc1과 tc2가 같은 주소 가짐)
  • tc2의 속성을 변경하면 tc1도 같이 변경 된다.
num = 100
str = hello
num = 100
str = hello
2799792540560
2799792540560
---------------
num = 3.14
str = hello
num = 3.14
str = hello
2799792540560
2799792540560
---------------
  • 깊은 복사1. copy모듈 사용
import copy

#생성자 호출
tc1 = TemCls(10,'hello')
tc2 = copy.copy(tc1)

tc1.printClsInfo()
tc2.printClsInfo()
print('='*30)
tc2.number = 30

tc1.printClsInfo()
tc2.printClsInfo()

-결과에서 tc2 속성을 변경할 때 tc2단독으로 변경 된 것을 볼 수 있다.

num = 10
str = hello
num = 10
str = hello
==============================
num = 10
str = hello
num = 30
str = hello

리스트에서 얕은복사, 깊은복사

  • 얕은복사
import copy

scores = [1,2,3,4,5]
scoresCopy  = []

scoresCopy = scores
print(f'{id(scores)}')
print(f'{id(scoresCopy)}')
#참조하는 주소가 같다 ==같은 객체 주소를 참조한다.
2265950669952
2265950669952

-깊은복사1. append()사용

import copy

scores = [1,2,3,4,5]
scoresCopy  = []

for s in scores:
	<#append() : ()안의 인수가 scoreCopy리스트에 추가된다.>
    scoresCopy.append(scores)

print(f'{id(scores)}')
print(f'{id(scoresCopy)}')
#주소가 다르다 == 참조하는 객체 주소도 다르다 
2543462730880
2543462501184

-깊은복사2. exrend()사용

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

<#extend() : ()안의 값을 리스트에 추가한다.>
scoresCopy.extend(scores)

print(f'{id(scores)}')
print(f'{id(scoresCopy)}')
  • 깊은복사3. 리스트 자체적으로 깊은 복사를 하는 매소드가 있다.(copy)
scores = [9,8,5,7,6,10]
scoresCopy =[]

scoresCopy = scores.copy()
print(f'{id(scores)}')
print(f'{id(scoresCopy)}')

예제1

  • sort() : 리스트를 오름차순 정리
  • pop(n) : n-1번째 값 제외한 리스트
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)
plaCopSco.pop()

#선수 원본점수, 최고최저점 뺀 리스트 출력
print(f'plaOriSco : {plaOriSco}')
print(f'plaCopSco : {plaCopSco}')

#원본 점수 총합, 평균
oriTot = sum(plaOriSco)
oriAvg = round(sum(plaOriSco)/len(plaOriSco),2)
print(f'Original Total: {oriTot}')
print(f'Original Average: {oriAvg}')

#복사 점수 총합, 평균
copTot = round(sum(plaCopSco),2)
#
copAvg = round(sum(plaCopSco)/len(plaCopSco),2)
#
print(f'Copy Total: {copTot}')
print(f'Copy Average: {copAvg}')

result = round(oriAvg - copAvg,2)
print(f'oriAvg - copAvg: {result}')
  • 강의 강사님은 copAvg를 구할 때 oriTot을 나누셨는데 이유를 모르겠다...

9) 클래스 상속

클래스는 또 다른 클래스를 상속해서 내 것 처럼 사용 할 수 있다.

1. 상속하는 법

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

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


<#TurboCar가 NormalCar를 상속 받는다>
class TurboCar(NormalCar):
    def turbo(self):
        print('[TurboCar] turbo() called!!')

myTurboCar = TurboCar()

myTurboCar.turbo()
myTurboCar.drive()
myTurboCar.back()
[TurboCar] turbo() called!!
[NormalCar] drive called!!
[NormalCar] back called!!

실습1.

덧셈,뺄셈 기능이 있는 클래스를 만들고, 이를 상속하는 클래스를 만들어서 곱셈과 나눗셈 기능을 추가해보자.

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

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

class CalculatorMD(CalculatorPS):
    def mul(self,n1,n2):
        return n1*n2
    def div(self,n1,n2):
        return n1/n2

myCal = CalculatorMD()
print(f'n1+n2 = {myCal.add(10,20)}')
print(f'n1-n2 = {myCal.sub(10,20)}')
print(f'n1*n2 = {myCal.mul(10,20)}')
print(f'n1/n2 = {myCal.div(10,20)}')
n1+n2 = 30
n1-n2 = -10
n1*n2 = 200
n1/n2 = 0.5

10) 생성자

객체가 생성 될 때 생성자를 호출 하면 __init__()가 자동 호출 된다. 
class Calculator:

	#__init__()가 속성을 초기화 한다.
    def __init__(self,n1,n2):
        print('[Calculator] called')
        self.num1 = n1
        self.num2 = n2

 #생성자 호출(__init__()가 호출)
cal = Calculator(10,20)

print(f'cal num1 = {cal.num1}')
print(f'cal 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):
        print('[C_Class] __init__ called!')

        #상위 클래스(P_Class)의 이닛매소드도 사용하겠다
        #P_Class.__init__(self, cNum1, cNum2)
        #좀 더 세련되게 super()는 상위클래스, super()뒤 init에는 self생략
        super().__init__(cNum1,cNum2)

        self.cNum1 = cNum1
        self.cNum2 = cNum2

cls = C_Class(10,20)

실습1.

중간고사 클래스와 기말고사 클래스를 상속관계로 만들고 각각의 점수를 초기화 하자.
또한 총점 및 평균을 반환하는 기능도 만들어 보자

class MidExam:

    def __init__(self, s1, s2, s3):
        print(f'[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__()')
        
        #상위클래스 MidExam의 __init__() 초기화
        super().__init__(s1,s2,s3)

        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'totalScore : {exam.getTotalScore()}')
print(f'AverageScore : {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
totalScore : 518
AverageScore : 86.33

11) 다중상속

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.drive()
myCar.turbo()
myCar.fly()
drive() method called
turbo() method called
fly() method called

12) 오버라이딩

하위 클래스에서 상위 클래스의 매서드를 재정의 하는 것

class Robot:

    def __init__(self,c, h, w):
        self.color = c
        self.height = h
        self.weight = w
	
    
    def fire(self):
        print('[미사일 발사]')

    def printRobotInfo(self):
        print(f'self.color ={self.color}')
        print(f'self.height ={self.height}')
        print(f'self.weight ={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.printRobotInfo()
myRobot.fire()
  • class Robot에서 기능 매서드 fire를 Robot클래스를 상속받는 NewRobot클래스에서 다시 정의 한다. --> 오버라이딩
self.color =red
self.height =200
self.weight =300
레이저발사

13) 추상클래스

  • 상위클래스에서 하위클래스에 메서드 구현을 강요하는 것.
  • 더 자세히 말하면 상위 클래스에서는 매서드 선언만 하고 하위 클래스에서 해당 매서드 구현

사용하는 이유

하위 클래스들의 입맛에 맞게 매소드 구현을 하기 위해서

추상클래스 명시 법

  1. abc 모듈에서 ABCMeta(), abstractmethod()를 import 한다.
  2. 해당 클래스에 metaclass=ABCMEta 를 상속해준다.
  3. 해당 기능 매소드 정의 전에 @absreactmethod 입력해준다.
  4. 하위 클래스에서 해당 기능 매소드를 구현

예시1

#추상클래스 명시에 필요한 모듈 import
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 AirLine(Airplane):
    def __init__(self,c):
        self.color = c
    
    #기능 구현
    def flight(self):
        print('시속 400km/h 비행')

al = AirLine('red')
al.flight()
  • 결과에서 Airplane을 상속받은 AirLine의 flight기능 구현한게 출력된다.
시속 400km/h 비행

5. 예외(exception)

문법적인 문제는 없으나 실행 중 발생하는 예상하지 못한 문제

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

1) 예외 처리

- try ~ except

예외 발생 예쌍 구문을 try ~ except로 감싼다.

n1 = 10
n2 = 0

#나눗셈은 0으로 나누지 못한다. ->예상 예외 구간
try:
    print(f'n1 / n2 ={n1/n2}')
#예외가 발생하면 except 실행, 발생하지 않으면 계속 실행
except:
    print('예상치 못한 문제 발생')
    print('다음으로 프로그램 실행')
print(f'n1 + n2 ={n1+n2}')
print(f'n1 * n2 ={n1*n2}')
예상치 못한 문제 발생
다음으로 프로그램 실행
n1 + n2 =10
n1 * n2 =0

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

nums = []

n =1
while n<6:

    try:
        data = int(input('input number : '))
    except:
        print('예외 발생!')
        continue

    nums.append(data)
    n +=1
print(f'nums : {nums}')
input number : 1
input number : 2
input number : f
예외 발생!
input number : 3
input number : b
예외 발생!
input number : 4
input number : 5
nums : [1, 2, 3, 4, 5]

- try~except~else

try에서 예외 발생하면 except로 진행
try에서 예외 발생 않하면 else 진행

실습1. 사용자로부터 숫자 5개를 입력받아 짝수,홀수, 실수로 구분해서 각각을 리스트에 저장하는 프로그램을 만들어 보자.

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

n = 1
while n<6:
    try:
        num = float(input('input num'))
    except:
        print('예외 발생')
        continue
    else:
        if num - int(num) != 0:
            print('float number!')
            floatList.append(num)
        else:
            if num % 2 == 0:
                print('even number!')
                eveList.append(int(num))
            else:
                print('odd number!')
                oddList.append(int(num))

    n+=1

print(f'eveList = {eveList}')
print(f'oddList = {oddList}')
print(f'floatList = {floatList}')
input num1
odd number!
input num2
even number!
input num3
odd number!
input num3.14
float number!
input numd
예외 발생
input num5
odd number!
eveList = [2]
oddList = [1, 3, 5]
floatList = [3.14]

- finally

예외 발생과 상관없이 항상 실행 하려고 할때

try:
    inputdata = input('number:')
    numInt = int(inputdata)
except:
    print('예외 발생')
    print('not number')
else:
    if numInt % 2 == 0:
        print('짝수')
    else:
        print('홀수')

finally:
    print(f'inputdata : {inputdata}')
number:d
예외 발생
not number
inputdata : d

- 예외 담당 클래스 Exception

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

profile
취업공부

0개의 댓글