데이터분석

[23.06.09] Python 객체 지향, 모듈 - 06(1)

gmwoo 2023. 6. 9. 17:16

1. 객체 지향

 - 추상화: 어떤 물체의 특징을 파악하고 고유의 특징을 뽑아내는 것
   -> 사람이 사물을 바라보는 형태로 프로그램을 함
 - 변수와 함수는 별개, 따로따로 만듦
 - 변수도 많고 함수도 많아 관리가 어려움
    -> 이 중에 어떤 변수와 함수는 서로 관련이 있음
    -> 관련있는 변수와 함수를 묶어보자 => 클래스(사용자가 만드는 데이터 타입) 
    -> list, dict, tuple : 시스템이 만드는 클래스, 내장 라이브러리, 내장 클래스
    -> 위의 클래스들을 부품형 클래스 - 부품형 클래스 만드는 방법
    -> 부품을 사용하여 완성형 클래스를 만드는 방법은 서로 다름
 - 최종 목적: 프로그램을 빠르고 확장성 있도록 만들기 위함
    -> 관련있는 것들끼리 묶어서 클래스를 만들기 (list, dict 등)
    -> 클래스는 객체를 만들어야 사용 가능

a = list()
 # a=[], list 타입의 객체를 생성함. 생성 공간은 heap(자유 메모리) 이고 객체의 첫 위치를 전달
 # 만약, 메모리가 부족하면 None 반환

 - 파이썬은 변수를 주로 public 
 
예제 1) 사람의 개인정보를 만듦

# 사람의 개인정보를 만듦
class Person:
    name = "홍길동"
    age = 23
  
p1 = Person()  # 객체 생성, 이 객체를 '인스턴스'라고도 부름
print(p1.name)
print(p1.age)

 - java 와 달리 함수 밖에 변수를 선언했을 경우, 메모리가 클래스 지정할 때 하나만 만들어짐

# 사람의 개인정보를 만듦
class Person:
    name = "홍길동"
    age = 23
    phone = []  # 클래스 정의할 때 딱 한 번 실행
    ######## 이 위치에 list나 dict 같은 객체를 선언할 경우 객체가 클래스 정의 시 딱 한 번만 만들어져서 공유되기 때문에 가급적 이 위치에 변수 만들지 말자

p1 = Person()  # 객체 생성, 이 객체를 '인스턴스'라고도 부름
p1.phone.append("010-0000-0000")
print(p1.name)
print(p1.age)
print(p1.phone)

# 함수 밖에 변수를 선언했을 경우, 메모리가 클래스 지정할 때 하나만 만들어짐
# 따라서 생성자에서 만들어야 같은 주소를 사용하지 않음
p2 = Person()  
p2.phone.append("010-0000-2222")
p2.name = "임꺽정"  # 이 때, p2용의 name 속성을 만들어서 데이터 저장
print(p2.name)
print(p2.age)
print(p2.phone)

# 출력
23
['010-0000-0000']
임꺽정
23
['010-0000-0000', '010-0000-2222']

 
 - 생성자: 특별한 유형의 함수, 객체 생성 시 자동으로 호출되는 메서드
 - __init__
 - 함수나 변수 중에 '__(언더바 2개)'로 시작함 -> 파이썬이 특수목적으로 만들었다는 뜻

    1) 첫 번째 인자로 객체에 대한 참조가 전달되도록 되어 있어서 꼭 변수명이 self 일 필요는 없지만 암묵적으로 self를 사용함
 
    2) 클래스 안에 선언된 함수는 첫 번째 인자로 객체에 대한 참조를 전달하도록 되어있음
def __init(self): 
    # 첫 번째 인자로 객체에 대한 참조가 전달되도록 되어 있어서
    # 꼭 변수명이 self 일 필요는 없지만 암묵적으로 self를 사용함
    # 클래스 안에 선언된 함수는 첫 번째 인자로 객체에 대한 참조를 전달하도록 되어있음
# 사람의 개인정보를 만듦
class Person:
    # name = "홍길동"
    # age = 23
    # phone = []  # 클래스 정의할 때 딱 한 번 실행
    ######## 이 위치에 list나 dict 같은 객체를 선언할 경우 객체가 클래스 정의 시 딱 한 번만 만들어져서 공유되기 때문에 가급적 이 위치에 변수 만들지 말자
    
    def __init__(self): 
        self.name="조승연"
        self.age=28
        self.phone=[]
        print("생성자 호출")
    
# 변수 생성은 생성자에서 하자    
    
p1 = Person()  # 객체 생성, 이 객체를 '인스턴스'라고도 부름
p1.phone.append("010-0000-0000")
print(p1.name)
print(p1.age)
print(p1.phone)

# 함수 밖에 변수를 선언했을 경우, 메모리가 클래스 지정할 때 하나만 만들어짐
p2 = Person()  
p2.phone.append("010-0000-2222")
p2.name = "임꺽정"  # 이 때, p2용의 name 속성을 만들어서 데이터 저장
print(p2.name)
print(p2.age)
print(p2.phone)

 - 총 코드

# 사람의 개인정보를 만듦
class Person:
    # name = "홍길동"
    # age = 23
    # phone = []  # 클래스 정의할 때 딱 한 번 실행
    ######## 이 위치에 list나 dict 같은 객체를 선언할 경우 객체가 클래스 정의 시 딱 한 번만 만들어져서 공유되기 때문에 가급적 이 위치에 변수 만들지 말자
    
    def __init__(self, name="홍길동", age=20): 
        self.name=name
        self.age=age
        self.phone=[]
        print("생성자 호출")
    
    def output(self):
        # 반드시 self로 접근
        print(f"{self.name} {self.age}")
    
    
# 변수 생성은 생성자에서 하자    
    
p1 = Person()  # 객체 생성, 이 객체를 '인스턴스'라고도 부름
p1.phone.append("010-0000-0000")
print(p1.name)
print(p1.age)
print(p1.phone)

# 함수 밖에 변수를 선언했을 경우, 메모리가 클래스 지정할 때 하나만 만들어짐
p2 = Person()  
p2.phone.append("010-0000-2222")
p2.name = "임꺽정"  # 이 때, p2용의 name 속성을 만들어서 데이터 저장
print(p2.name)
print(p2.age)
print(p2.phone)
    
p1.output()
p2.output()

# 객체 생성 방법이 다양해짐
p3 = Person("김종국")
p4 = Person("유재석", 52)
p5 = Person(age=35)

p3.output()
p4.output()
p5.output()

 
문제 1) 주급 계산

# 클래스 설계할 때 - 한 사람 분의 데이터 처리
class Pay:
    def __init__(self, name="홍길동", work_time=40, per_pay=10000):
        self.name = name
        self.work_time = work_time
        self.per_pay = per_pay
        self.calculate()
    
    def calculate(self):
        self.pay = self.work_time * self.per_pay  # 중간에 변수 추가를 해도 함
        
    def output(self):
        print(f"{self.name} {self.work_time} {self.per_pay} {self.pay}")
        
class PayManager:
    payList = []
    def __init__(self):
        self.payList.append(Pay("A", 30, 20000))
        self.payList.append(Pay("B", 40, 30000))
        self.payList.append(Pay("C", 20, 10000))
        self.payList.append(Pay("D", 15, 20000))
        self.payList.append(Pay("E", 25, 30000))
    
    def append(self):
        pay = Pay()
        pay.name = input("이름: ")
        pay.work_time = int(input("일 한 시간: "))
        pay.per_pay = int(input("시간 당 급여액: "))
        pay.calculate()
        self.payList.append(pay)

    def output(self):
        for pay in self.payList:
            pay.output()
        
    def menu(self):
        print("1. 추가")
        print("2. 출력")
        print("0. 종료")
    
    def start(self):
        while True:
            self.menu()
            sel = input("선택: ")
            if sel == "1":
                self.append()
            elif sel == "2":
                self.output()
            else:
                print("프로그램 종료")
                return

# 하나의 파일에 하나의 클래스를 만든다
# 다른 파일에 있을 때 모듈을 가져오려면 import 를 사용한다
# 외부 모듈 불러오기

mgr = PayManager()
mgr.start()

 

2. 모듈

# mymodule.py

def add(x, y):
    return x+y

def sigma(limit=10):
    s = 0
    for i in range(1, limit+1):
        s += i
    return s

class MyCalc:
    def __init__(self, x=0, y=0):
        self.x = x
        self.y = y
    def add(self):
        return self.x + self.y
    def sub(self):
        return self.x - self.y
    
print(__name__)   # 시스템이 제공하는 내부 변수
print(add(4,5))
print(sigma())
print(sigma(100))

calc = MyCalc(7,8)
print(calc.add())
print(calc.sub())

- mymodule.py를 import 하여 불러오기

import mymodule   # mymodule.py 불러오기

print(mymodule.add(6,7))
print(mymodule.sigma(1000))

m1 = mymodule.MyCalc(10,20)
print(m1.add())
print(m1.sub())

from mymodule import add, sigma, MyCalc  # 위 코드보다 간결해짐

print(add(11,12))
print(sigma(20))

m2 = MyCalc(9,5)
print(m2.add())
print(m2.sub())

from mymodule import add, sigma, MyCalc as mc   # 위 코드보다 간결해짐
m3 = mc(17,19)
print(m3.add())
print(m3.sub())

 
예제 1) 가위바위보
 - gameData.py: 한 게임 분의 코드를 먼저 만듦
 - gameManager.py: gameData.py를 통해 두 번째 게임부터 모든 히스토리와 최종 승률 출력 

# gameData.py

# 한 게임 분의 코드
import random

class GameData:   # 클래스명은 가급적 첫 글자를 대문자로
    COMWIN = 1
    PERWIN = 2
    DRAW = 3
    
    def __init__(self):      # 생성자 만들기
        self.computer = random.randint(1,3)
        self.person = int(input("1. 가위, 2. 바위, 3. 보 "))
        self.winner = self.whoIsWinner()   # 함수 호출
        
    def whoIsWinner(self):   # gameinfo 라는 dict 타입 대신 self로
        if self.computer == self.person:
            return self.DRAW   # 비김
        
        if self.computer == 1 and self.person == 2:
            return self.PERWIN   # 사람이 이김
        if self.computer == 1 and self.person == 3:
            return self.COMWIN   # 컴퓨터가 이김
        
        if self.computer == 2 and self.person == 1:
            return self.COMWIN   # 컴퓨터가 이김
        if self.computer == 2 and self.person == 3:
            return self.PERWIN   # 사람이 이김
        
        if self.computer == 3 and self.person == 1:
            return self.PERWIN   # 사람이 이김
        if self.computer == 3 and self.person == 2:
            return self.COMWIN   # 컴퓨터가 이김
        
    def output(self):
        words = ["", "가위", "바위", "보"]
        words2 = ["", "컴퓨터승", "사람승", "무승부"]
        
        print(f"컴퓨터:{words[self.computer]}, 사람:{words[self.person]} {words2[self.winner]}")
            
if __name__ == "__main__":
    game = GameData()
    game.output()
# gameManager.py

from gameData import GameData    # from 파일명 import 함수, 변수, 클래스 등

class GameManager:
    gameList = list()  # 앞으로 하는 게임은 여기에 저장하려 함
    def __init__(self):
        print("게임을 시작하지")
        
    def gameStart(self):
        while True:
            game = GameData()
            game.output()
            self.gameList.append(game)
            again = input("계속 할텨? ")
            if again != "Y" and again != "y":
                return
    
    # 그 동안 했던 게임의 히스토리를 모두 출력
    def gameOutput(self):
        for game in self.gameList:
            game.output()
            
    def gameStatics(self):
        statics = [0, 0, 0, 0]
        for game in self.gameList:
            # 컴퓨터가 이기면 statics의 1번방 증가, 사람이 이기면 2번방 증가, 비기면 3번방 증가
            statics[game.winner] +=1
            statics[0] += 1
        print(f"갯수 - 컴퓨터승 : {statics[1]}, 사람승수: {statics[2]}, 무승부: {statics[3]}")
        print("--- 각 승률 ---")       
        print(f"컴퓨터승 : {statics[1]/statics[0]}")
        print(f"사람승수: {statics[2]/statics[0]}")
        print(f"무승부: {statics[3]/statics[0]}")
            
if __name__ == "__main__":
    mgr = GameManager()
    mgr.gameStart()
    mgr.gameOutput()
    mgr.gameStatics()
반응형