데이터 공부/Python

[나도코딩] 파이썬 기본편 6-11

민몽 2023. 1. 10. 23:26

안녕하세요 민몽입니다 :>

이 전에 포스팅했던 글에 이어서 유튜버 '나도코딩'님의 파이썬 기본편 강의를 마무리 해보려고 합니다.

뒤로 갈수록 조금 어려워지기도 하고 스타크래프트에 대해서 알았다면 더 재미있게 실습했을텐데

잘 모르는 분야라 아쉬웠어요 ㅠ-ㅠ.. (어릴 때 오빠랑 몇번 같이 했던 기억이 있긴 하네요 ㅋㅋㅋ)

프로그래밍 수업에서 C++로만 배웠던 클래스나 상속, 모듈같은 내용들을 파이썬으로도 다뤄볼 수 있어 좋았어요.

 

아래는 공부하면서 정리했던 내용들입니다.


<6.반복문>

# Quiz) 당신은 Cocoa 서비스를 이용하는 택시 기사님입니다.
# 50명의 승객과 매칭 기회가 있을 때, 총 탑승 승객 수를 구하는 프로그램을 작성하시오.
# 조건 1 : 승객 별 운행 소요 시간은 5 ~ 50 분 사이의 난수로 정해집니다.
# 조건 2 : 당신은 소요 시간 5분 ~ 15분 사이의 승객만 매칭해야 합니다.
# 출력 예제
# [O] 1번째 손님 ( 소요시간 : 15분 )
# [ ] 2번째 손님 ( 소요시간 : 50분 )
# 총 탑승 승객 : 2분

from random import *
time = randint(5,50)

def total_customer():
    index = 0 # 총 승객 수
    for customer in range(1,51): # 총 승객 50명
        time = randint(5,50) # 소요 시간
        if time >= 5 and time <= 15: # 매칭 성공
            print("[O] {0}번째 손님 ( 소요시간 : {1}분 ) ".format(customer,time))
            index += 1 # 탑승 수 증가 처리
        else: # 매칭 실패
            print("[ ] {0}번째 손님 ( 소요시간 : {1}분 ) ".format(customer,time))
    print("총 탑승 승객 : {0}분".format(index))

total_customer()


< 7. 가변인자>
- 한 변수에 여러 인자들을 자유롭게 입력하고싶은 경우 가변인자 사용
- 변수 앞에 별표(*) 사용
→ 아직 잘 모르겠음,, 좀 더 찾아보기 !
+ 스터디하면서 알게 된 내용 추가 !
- 매개변수 앞에 * 붙이기
- 입력값을 전부 모아서 튜플로 반환
- 변수 이름은 아무거나 사용해도 상관없으나 *args가 관례적으로 자주 사용됨.

def profile(name, age, *language):
    print("이름 : {0}\t나이 : {1}\t".format(name, age), end=" ")
    for lang in language:
        print(lang, end=" ")
    print()


<7-7. 퀴즈>

# Quiz) 표준 체중을 구하는 프로그램을 작성하시오

# * 표준 체중 : 각 개인의 키에 적당한 체중

# (성별에 따른 공식)
# 남자 : 키(m) x 키(m) x 22
# 여자 : 키(m) x 키(m) x 21

# 조건 1 : 표준 체중은 별도의 함수 내에서 계산
#         * 함수명 : std_weight
#         * 전달값 : 키(height), 성별(gender)
# 조건 2 : 표준 체중은 소수점 둘째자리까지 표시

# (출력 예제)
# 키 175cm 남자의 표준 체중은 67.38kg 입니다.

def std_weight(height, gender):
    if gender == "여자":
        weight = round((height/100)*(height/100)*21,2)
    elif gender == "남자":
        weight = round((height/100)*(height/100)*22,2)
    return height, gender, weight

height,gender,weight = std_weight(175,"남자")
height,gender,weight = std_weight(158,"여자")

print("키 {0}cm {1}의 표준 체중은 {2}kg 입니다.".format(height, gender, weight))


< 8-1. 표준 입출력>

import sys
print("Python","Java", file = sys.stdout) # 표준 출력
print("Python","Java", file = sys.stderr) # 표준 에러


scores = {"수학":0 , "영어":50, "코딩":100}
for subject, score in scores.items():
   print(subject.ljust(8), str(score).rjust(4), sep = ":")


- 딕셔너리 키, 값 각각 뽑아내기 = for key, values in dict.items()
- 문자열.ljust(8) : 8칸 만큼의 공간 확보 후 왼쪽 정렬
- 문자열.rjust(4) : 4칸 만큼의 공간 확보 후 오른쪽 정렬

for num in range(1,21):
    print("대기번호 : " + str(num).zfill(3))

 

- 1,2,3 → 001, 002, 003 이런 식으로 출력하기
- 문자열.zfill(n) 사용 → n만큼의 공간 확보 후 빈 공간은 0으로 채움.

answer = input("아무 값이나 입력하세요 : ") # 항상 문자열 형태로 저장됨 !
print("입력하신 값은" + answer + "입니다.")


<8-2. 다양한 출력 포맷>

# 양수일 땐 +로 표시, 음수일 땐 -로 표시
print("{0: >+10}".format(500))
# 3자리마다 콤마 찍어주기 , + - 부호도 붙이기
print("{0:+,}".format(10000000))


<8-3. 파일 입출력>

- 파일 입력하기

score_file = open("score.txt","w", encoding = "utf8") # "w" : 쓰기모드 writing , "a" : 이어쓰기 ( append )
print("수학 : 0", file = score_file) # 파일 내용
print("영어 : 50", file = score_file)
score_file("\n과학: 20") # 자동 줄바꿈 없음
score_file.close() # 파일 닫기


- 파일 출력하기

score_file = open("score.txt","r", encoding = "utf8") # "r" : 읽기전용 read
#print(score_file.read()) # 전부 읽어오기
print(score_file.readline(), end = "") # 줄별로 읽기, 커서는 다음 줄로 이동
print(score_file.readline(), end = "")
score_file.close()


- 반복문으로 읽어오기

score_file = open("score.txt","r", encoding = "utf8")
while True:
    line = score_file.readline()
    if not line:
        break
    print(line, end ="")
score_file.close()

 

- 리스트 형태로 저장 후 출력 (readlines)

score_file = open("score.txt","r", encoding = "utf8")
lines = score_file.readlines() # 리스트 형태로 저장
for line in lines:
    print(line, end = "")
score_file.close()


<8-4. pickle>
- 프로그램 상 사용하고있는 데이터를 파일 형태로 저장해줌.

import pickle
# pickle로 저장
profile_file = open("profile.pickle",'wb') # 항상 binary 타입으로 지정 필수, encoding 지정 필요 X
profile = {"이름":"박명수","나이":30,"취미":["축구","골프","코딩"]}
print(profile)
pickle.dump(profile, profile_file) # profile에 있는 정보를 file에 저장
profile_file.close()
# pickle 불러오기
profile_file = open("profile.pickle",'rb')
profile = pickle.load(profile_file) # file에 있는 정보를 profile에 불러오기
print(profile)
profile_file.close()


<8-5. with>

with open("profile.pickle","rb") as profile_file: # profile.pickle의 내용을 profile_file 변수에 저장
    print(pickle.load(profile_file))
# close 필요 없음.


# 8장 퀴즈

# Quiz ) 당신의 회사에는 매주 1회 작성해야하는 보고서가 있습니다.
# 보고서는 항상 아래와 같은 형태로 출력되어야 합니다.

# - X 주차 주간보고 -
# 부서 :
# 이름 :
# 업무 요약 :

# 1주차부터 50주차까지의 보고서 파일을 만드는 프로그램을 작성하시오.
# 조건 : 파일명은 '1주차.txt','2주차.txt',...와 같이 만듭니다.

for number in range(1,51):
    with open(str(number)+"주차","w",encoding='utf8') as report:
        report.write("- {0} 주차 주간보고 -\n부서 :\n이름 :\n업무 요약 :".format(number))

 

- 처음에는 report.write 안쓰고 print로 했다가 파일 내용은 하나도 안들어가고 출력만 됨 .. 
- 이름도 str로 안 감싸서 에러 났었음. + 로 문장 연결할때는 항상 문자열로 바꿔주기 !!

<9-1. 클래스>

class Unit:
    def __init__(self, name, hp, damage):
        self.name = name
        self.hp = hp
        self.damage = damage
        print("{0} 유닛이 생성 되었습니다.".format(self.name))
        print("체력 {0}, 공격력 {1}".format(self.hp, self.damage))

marine1 = Unit("마린",40,5)
marine2 = Unit("마린",40,5)
tank = Unit("마린",150,35)


- __init__ : 파이썬의 생성자
- marin1, tank : Unit 클래스의 인스턴스

상속

# 일반 유닛
class Unit:
    def __init__(self, name, hp): # 항상 맨 앞에 self 넣어야함 !!
        self.name = name
        self.hp = hp

# 공격 유닛
class AttackUnit(Unit): # Unit 클래스 상속 받음
    def __init__(self, name, hp, damage): # 생성자 정의
        Unit.__init__(self,name,hp) # name, hp 는 Unit클래스에서 상속받음
        self.damage = damage
    def attack(self, location):
        print("{0} : {1} 방향으로 적군을 공격 합니다. [공격력 {2}]"\
            .format(self.name, location, self.damage))
    def damaged(self, damage):
        print("{0} : {1} 데미지를 입었습니다".format(self.name, damage))
        self.hp -= damage
        print("{0} : 현재 체력은 {1} 입니다".format(self.name, self.hp))
        if self.hp <= 0:
            print("{0} : 파괴되었습니다.".format(self.name))

# 날 수 있는 유닛
class Flyable:
    def __init__(self, flying_speed):
        self.flying_speed = flying_speed
        
    def fly(self, name, location):
        print("{0} : {1} 방향으로 날아갑니다. [속도 {2}]"\
            .format(name, location, self.flying_speed))
    
# 공중 공격 유닛 클래스
class FlyableAttackUnit(AttackUnit, Flyable): # 다중상속
    def __init__(self, name, hp, damage, flying_speed):
        AttackUnit.__init__(self, name, hp, damage) # name, hp, damage는 AttackUnit 클래스에서 상속받음
        Flyable.__init__(self,flying_speed)    # flying_speed 는 Flyable 클래스에서 상속 받음
        
# 발키리 : 공중 공격 유닛
valkyrie = FlyableAttackUnit("발키리",200,6,5)
valkyrie.fly(valkyrie.name, "3시")

 

<9-7. 메소드 오버라이딩>
- 위의 코드에서 move 함수만 추가함 !

# 일반 유닛
class Unit:
    def __init__(self, name, hp, speed):
        self.name = name
        self.hp = hp
        self.speed = speed
    def move(self, location):
        print("[지상 유닛 이동]")
        print("{0} : {1} 방향으로 이동합니다. [속도 {2}]"\
            .format(self.name, location, self.speed))

# 공격 유닛
class AttackUnit(Unit):
    def __init__(self, name, hp,speed, damage):
        Unit.__init__(self,name,hp, speed)
        self.damage = damage
    def attack(self, location):
        print("{0} : {1} 방향으로 적군을 공격 합니다. [공격력 {2}]"\
            .format(self.name, location, self.damage))
    def damaged(self, damage):
        print("{0} : {1} 데미지를 입었습니다".format(self.name, damage))
        self.hp -= damage
        print("{0} : 현재 체력은 {1} 입니다".format(self.name, self.hp))
        if self.hp <= 0:
            print("{0} : 파괴되었습니다.".format(self.name))

# 날 수 있는 유닛
class Flyable:
    def __init__(self, flying_speed):
        self.flying_speed = flying_speed
        
    def fly(self, name, location):
        print("{0} : {1} 방향으로 날아갑니다. [속도 {2}]"\
            .format(name, location, self.flying_speed))
    
# 공중 공격 유닛 클래스
class FlyableAttackUnit(AttackUnit, Flyable):
    def __init__(self, name, hp, damage, flying_speed):
        AttackUnit.__init__(self, name, hp, 0, damage) # 지상 스피드 = 0
        Flyable.__init__(self, flying_speed)    
    
    def move(self, location):
        print("[공중 유닛 이동]")
        self.fly(self.name, location)
        
vulture = AttackUnit("벌쳐",80,10,20)
battlecruiser = FlyableAttackUnit("배들크루저",500,25,3)

# 지상 유닛 이동은 move, 공중 유닛 이동은 fly 로 매번 어떤 타입의 유닛인지 확인 필요함
# 메소드 오버라이딩으로 똑같이 move 함수를 쓰도록 !
vulture.move("11시")
# battlecruiser.fly(battlecruiser.name,"9시")
battlecruiser.move("9시")


<9-8. pass>

# 건물
class BuildingUnit(Unit):
    def __init__(self, name, hp, location):
        pass # 함수를 완성하지 않아도 완성된 것 처럼 넘어감.

supply_depot = BuildingUnit("서플라이 디폿",500,"7시")


<9-9. super>

class BuildingUnit(Unit):
    def __init__(self, name, hp, location):
        # Unit.__init__(self,name,hp,0)
        super().__init__(name,hp,0) # 괄호 필요, self X
        # 상속받는 부모 클래스의 인스턴스 초기화 가능
        self.location = location
- 다중 상속을 받는 경우

class Unit:
    def __init__(self):
        print("Unit 생성자")

class Flyable:
    def __init__(self):
        print("Flyable 생성자")

class FlyableUnit(Unit,Flyable):
    def __init__(self):
        #super().__init__() # 제일 처음 상속 받는 클래스에 대해서만 init 함수가 호출됨.
        # 명시적으로 각각의 부모클래스에 대해서 생성자 호출이 필요함.
        Unit.__init__(self)
        Flyable.__init__(self)
        
dropship = FlyableUnit()


텍스트로 실제 게임플레이처럼 시뮬레이션 돌려본 건 너무 길어서 깃헙에 업로드했습니다. 
https://github.com/alsrud2298/Python/blob/master/practice.py

 

<9장 퀴즈>

# Quiz) 주어진 코드를 활용하여 부동산 프로그램을 작성하시오.

# (출력 예제)
# 총 3대의 매물이 있습니다.
# 강남 아파트 매매 10억 2010년
# 마포 오피스텔 전세 5억 2007년
# 송파 빌라 월세 500/50 2000년

# [코드]
class House:
    #매물 초기화
    def __init__(self, location, house_type, deal_type, price, completion_year):
        self.location = location
        self.house_type = house_type
        self.deal_type = deal_type
        self.price = price
        self.completion_year = completion_year

    
    #매물 정보 표시
    def show_detail(self):
        print(self.location, self.house_type, self.deal_type,\
                self.price, self.completion_year)

houses = []    
h1 = House("강남","아파트","매매","10억","2010년")
h2 = House("마포","오피스텔","전세","5억","2007년")
h3 = House("송파","빌라","월세","500/50","2000년")
houses.append(h1)
houses.append(h2)
houses.append(h3)

print("총 {0}대의 매물이 있습니다.".format(len(houses)))
for house in houses:
    house.show_detail()


- 생성된 인스턴스 개수를 어떻게 세야하나.. C++ 할떄는 count 변수 추가해서 어떻게 했던 것 같은데 파이썬은 그게 안되네 .. 고민하다가 결국 해결 못해서 해답을 봤습니다..
→ 그냥 리스트에 집어넣고 길이 재면 되는 거였음.. 리스트에 넣으니까 출력도 간단 .. ! 

<10-1 예외처리 >

# 예외처리
try:
    print("나누기 전용 계산기입니다.")
    nums = []  
    nums.append(int(input("첫 번째 숫자를 입력하세요 : ")))
    nums.append(int(input("두 번째 숫자를 입력하세요 : ")))
    #nums.append(int(nums[0] / nums[1]))
    print("{0} / {1} = {2}".format(nums[0], nums[1], nums[2]))
except ValueError:
    print("에러! 잘못된 값을 입력하였습니다.")
except ZeroDivisionError as err:
    print(err) # 발생하는 에러 출력
except Exception as err:
    print("알 수 없는 에러가 발생하였습니다.") # 나머지 모든 에러 처리
    print(err) # 어떤 에러인지 출력
#10-2 에러 발생시키기 #10-3 사용자 정의 예외처리 # 10-4 finally

class BigNumberError(Exception):
    def __init__(self, msg):
        self.msg = msg
    def __str__(self):
        return self.msg
try:
    print("한 자리 숫자 나누기 전용 계산기입니다.")
    num1 = int(input("첫 번째 숫자를 입력하세요 : "))
    num2 = int(input("두 번째 숫자를 입력하세요 : "))
    if num1 >= 10 or num2 >= 10:
        raise BigNumberError("입력값 : {0}, {1}".format(num1, num2)) # 위의 조건을 만족하는 경우 ValueError 발생
    print("{0} / {1} = {2}".format(num1, num2, int(num1/num2)))
except ValueError:
    print("잘못된 값을 입력하였습니다. 한 자리 숫자만 입력하세요.")
except BigNumberError as err:
    print("에러가 발생하였습니다. 한 자리 숫자만 입력하세요.")    
    print(err)
finally: # 오류 여부와 관련 없이 무조건 출력됨.
    print("계산기를 이용해주셔서 감사합니다.")


<10장 퀴즈>

# Quiz) 동네에 항상 대기 손님이 있는 맛있는 치킨집이 있습니다.
# 대기 손님의 치킨 요리 시간을 줄이고자 자동 주문 시스템을 제작하였습니다.
# 시스템 코드를 확인하고 적절한 예외처리 구문을 넣으시오.

# 조건 1 : 1보다 작거나 숫자가 아닌 입력값이 들어올 때는 ValueError 로 처리
#         출력 메시지 : "잘못된 값을 입력하였습니다."
# 조건 2 : 대기 손님이 주문할 수 있는 총 치킨량은 10마리로 한정
#         치킨 소진 시 사용자 정의 에러[SoldOutError]를 발생시키고 프로그램 종료
#         출력 메시지 : "재고가 소진되어 더이상 주문을 받지 않습니다."

chicken = 10
waiting = 1 # 홀 안에는 현재 만석. 대기번호 1부터 시작
class SoldOUtError(Exception):
    pass
        
while(True):
    try:
        print("[남은 치킨 : {0}]".format(chicken))
        order = int(input("치킨 몇 마리 주문하시겠습니까?"))
            
        if order > chicken: # 남은 치킨보다 주문량이 많을 때
            print("재료가 부족합니다.")
        elif order <1:
            raise ValueError
        else:
            print("[대기번호 {0}] {1} 마리 주문이 완료되었습니다."\
                .format(waiting, order))
            waiting += 1
            chicken -= order
        if chicken == 0:
            raise SoldOUtError
    except ValueError :
        print("잘못된 값을 입력하였습니다.")
    except SoldOUtError :
        print("재고가 소진되어 더이상 주문을 받지 않습니다.")
        break


- break → while 문 탈출

<11-1. 모듈>

- 같은 폴더 내 theather_module.py 파일 작성

import theater_module
theater_module.price(3)
theater_module.price_morning(4)
theater_module.price_soldier(5)

import theater_module as mv # 별명으로 설정
mv.price(3)
mv.price_morning(4)
mv.price_soldier(5)

from theater_module import * # 그냥 함수이름 만으로 사용 가능
price(3)
price_morning(4)
price_soldier(5)

from theater_module import price, price_morning # 특정 함수만 가져올 수 있음
price(5)
price_morning(5)

from theater_module import price_soldier as price # 가져온 특정 함수도 별명으로 사용 가능
price(4)


<11- 5. 패키지, 모듈 위치>
- 해당 패키지나 모듈의 위치 반환

import inspect
import random
print(inspect.getfile(random))


<11-6. pip install>
- pypi 사이트 활용

<11장 퀴즈>

# Quiz ) 프로젝트 내에 나만의 시그니처를 남기는 모듈을 만드시오

# 조건 : 모듈 파일명은 byme.py 로 작성

# ( 출력 예제 )
# 이 프로그램은 나도코딩에 의해 만들어졌습니다.
# 유튜브 : http://youtube.com
# 이메일 : nadocoing@gmail.com

#(모듈 사용 예제)
import byme
byme.sign()

# byme.py
def sign():
    print("이 프로그램은 나도코딩에 의해 만들어졌습니다.")
    print("유튜브 : http://youtube.com")
    print("이메일 : nadocoding@gmail.com")

끝 .. !