whatisthis?

Phython. 파이썬 코딩 기초편-10(上) 본문

WEB STUDY/PHYTHON | BACK-END

Phython. 파이썬 코딩 기초편-10(上)

thisisyjin 2021. 9. 20. 22:23

<Quiz>

동네에 항상 대기손님이 있는 치킨집이 있다.

대기 손님의 요리시간을 줄이고자 자동 주문 시스템을 제작했다.

시스템 코드를 확인하고 적절한 예외처리 구문을 넣으시오.

 

 

<조건>

1.. 1보다 작거나 숫자가 아닌값이 들어올때에는 valueError 로 처리

- 출력 메시지 : 잘못된 값을 입력하였습니다.

 

2. 대기 손님이 주문할 수 있는 총 치킨량은 10마리로 한정

치킨 소진시 사용자 정의 에러 [SoldOutError]를 발생시키고 프로그램 종료

- 출력 메시지 : 재고가 소진되어 더이상 주문을 받지 않습니다.

 

[코드]

chicken = 10
waiting = 1 #대기번호 1부터 시작
while (True):
    print("[남은 치킨 : {0}]".format(chicken))
    order = int(input("치킨 몇마리 드릴까요?"))
    if order > chicken:
        print("재료가 부족합니다.")
    else:
        print("[대기번호 {0}] {1}마리 주문이 완료되었습니다.".format(waiting, order))
        waiting += 1
        chicken -= order

 

___

 

내가 작성한 코드

 

class SoldOutError(Exception):
    pass



try:
    chicken = 10
    waiting = 1 #대기번호 1부터 시작
    while (True):
            print("[남은 치킨 : {0}]".format(chicken))
            order = int(input("치킨 몇마리 드릴까요?"))
            if order > chicken:
                print("재료가 부족합니다.")
            else:
                print("[대기번호 {0}] {1}마리 주문이 완료되었습니다.".format(waiting, order))
                waiting += 1
                chicken -= order

                if chicken == 0:
                    raise SoldOutError

                elif order < 1:
                    raise ValueError
                    

except ValueError:
    print("잘못된 값을 입력하였습니다.")


except SoldOutError:
    print("재고가 소진되어 더이상 주문을 받지 않습니다.")

 

 

** 내 코드의 잘못된점

 

1. elif order < 1의 위치

2. soldout시 프로그램이 종료되도록 하라고 했는데 안함 (while문을 빠져나오는 break이용)

 

 

만약 order에 -1을 입력한다면?

다음과 같이 주문이 완료되었다는 문구가 뜨므로,  내가 작성한 코드의

if문의 위치를 바꿔야 한다.

 

즉, if order > chicken 일때와

else 일때로 구분된 원래의 코드 사이에

elif 문으로 order이 1보다 작을때 raise ValueError 을 실행한다는 것을 추가해야한다.

 

왜냐하면 내가 원래 적었던 위치는 else문(주문이 완료되었다는 문구 프린트)를

실행하고 나서의 조건문이기 때문이다.

 

if에 의해

 

1. order > chicken 일때 = 재료가 부족합니다.

2. order이 1보다 작을때 (즉 0보다 작거나같을때) = ValueError

3. else(즉, order이 chicken보다 작고, 1보다 클때 = 주문이 완료되었습니다

 

이렇게 세가지로 명확히 구분되어야 한다.

 

그리고 else문 다음에 if chicken == 0일때 SoldOutError가 실행되도록 한다.

 

            if order > chicken:
                print("재료가 부족합니다.")

            elif order <= 0:
                raise ValueError

            else:
                print("[대기번호 {0}] {1}마리 주문이 완료되었습니다.".format(waiting, order))
                waiting += 1
                chicken -= order

            if chicken == 0:
                raise SoldOutError

 

그리고, SoldOutError 발생시 프로그램을 종료하라고 하였으므로

while문을 빠져나오는 break를 함께 써줘야한다.

 

해당 try-except 문에서

try문에 포함되는 부분은 print문 부터이다.

즉, 변수 선언과 while(True)부분은 try문의 바깥부분에 존재해야 한다.

 

** 간략하게 코드를 크게 보면 다음과 같다.

 

 

 

** 주의

 

while과 break의 위치

 

 


 

1. 모듈 (module)

= 필요한 것 끼리 부품처럼 만든 것. (함수 정의나 클래스 등을 담고있는 파일)

 

 

모듈 파일이 될 theater_module.py 파일을 생성한 후, 다음과 같이 코드를 작성한다.

**참고 > 모듈의 파일 확장자명도 똑같이 .py로 적으면 된다.

# 일반 가격
def price(people):
    print("{0}명 가격은 {1}원 입니다.".format(people, people * 10000))

# 조조 할인 가격
def price_morning(people):
    print("{0}명 조조 할인 가격은 {1}원 입니다.".format(people, people * 6000))

# 군인 가격
def price_soldier(people):
   print("{0}명 군인 할인 가격은 {1}원 입니다.".format(people, people * 4000))

 

 

 

그 다음, 모듈을 실행해볼 practice.py 파일에 다음과 같이 코드를 적는다.

방법 1) import를 사용하여 모듈 불러오기

 

import theater_module 

theater_module.price(3) # 3명 일반 가격
theater_module.price_morning(4) # 4명 조조할인 가격
theater_module.price_soldier(2) # 2명 군인할인 가격

 

1. import 모듈파일명

- 이때, 확장자명인 .py는 쓰지 않는다. 해당 파일과 모듈파일은 같은 폴더안에 있으므로 파일명만 작성해도 된다.

 

2. 모듈명.변수명(입력값)

- 이 역시 클래스와 비슷하게 .을 찍어서 모듈 내에서 정의한 함수, 변수를 사용할 수 있다.

 

 

+) as를 사용해서 모듈명 대신 별명을 붙여주어 사용해도 된다.

 

import theater_module as mv

mv.price(3) # 3명 일반 가격
mv.price_morning(4) # 4명 조조할인 가격
mv.price_soldier(2) # 2명 군인할인 가격

 

 

___

 

방법 2) from - import 문으로 불러오기

 

from theater_module import *

price(3) # 3명 일반 가격
price_morning(4) # 4명 조조할인 가격
price_soldier(2) # 2명 군인할인 가격

 

** 이때는 import * 로 전부 불러왔기 때문에,

theater_module.price(3) 과 같이 모듈명을 적고나서 쓸 필요가 없이

그냥 price(3)과 같이 함수명만 적으면 된다.

 

 

+) from - import 문에서 전부 가져오지 않는 경우 

 

필요한 함수(or 변수)만 import 할 수 있음.

from theater_module import price, price_morning

price(3) # 3명 일반 가격
price_morning(4) # 4명 조조할인 가격
price_soldier(2) # 2명 군인할인 가격

이와 같이 price와 price_morning에 대한 정보만 import 하면 된다.

 

이때, price_soldier에 대한 정보는 import 하지 않았으므로 해당 문구는 에러가 발생한다.

NameError: name 'price_soldier' is not defined

 

++) import 해서 가져온 함수도 as로 줄여서 쓸 수 있다.

from theater_module import price_morning as mor

mor(3) # 3명 조조할인 가격

 


2. 패키지

= 하나의 디렉토리(폴더) 에 모듈들을 모아놓은 집합. 

 

 

 

travel이라는 패키지 폴더안에 thai, vietnam이라는 이름의 모듈을 만들고,

__init__.py 파일도 만든다.

 

 

각 파일에 다음과 같이 코드를 입력한다.

 

1. thai.py

class ThailandPackage:
    def detail(self):
        print("[태국 패키지 3박 5일] 방콕, 파타야 여행 50만원")

 

2. vietnam.py

class VietnamPackage:
    def detail(self):
        print("[베트남 패키지 3박 5일] 다낭 효도 여행 60만원")

 

** 주의 > 패키지 폴더와 같은 위치에 있는 practice.py 파일을 열어서 다음과 같이 작성.

 

 

import travel.thai

trip_to = travel.thai.ThailandPackage()
trip_to.detail()

 

패키지폴더 안에 있는 모듈파일을 불러오는 방법

 

1. import 패키지명.모듈명
2. from 패키지명 import 모듈명
3. from 패키지명.모듈명 import 함수or클래스명

 

 

 

**주의 > import로는 모듈이나 패키지만 가능. 클래스나 함수는 바로 import로 불러올 수 X.

예 - import trave;.thai.ThailandPackage (X)

 

BUT. from-import 구문에서는 함수나 클래스를 import로 불러올 수 있다.

 

import 문 클래스, 함수를 import로 직접 불러올 순 없음.
임의의 변수로 불러와야함.

예- trip = travel.thai.ThailandPackage 
from - import 구문 클래스, 함수를 import로 불러올 수 있음.

예 -from travel.thai import ThailandPackage

 

 


 

3. __all__

 

패키지를 from - import로 가져올때

from travel import * 과 같이 입력하면, travel 패키지 안의 모듈을 이용할 수 없다.

이때, __all__을 이용하면 된다.

 

아까 패키지 폴더안에 생성해놨던 __init__ 파일에 다음과 같은 코드를 작성한다.

 

__all__ = ["vietnam"]

 

__init__파일에 다음과 같은 코드로 인해

vietnam이라는 이름의 모듈의 모든 내용이 __all__로 전달된다.

 

다시, practice.py 파일로 돌아가보면

from travel import *
trip_to = vietnam.VietnamPackage()
trip_to.detail()

import * 을 통해 이제는 모듈의 내용을 전부 불러와 이용 할 수 있다.

 

+) thai.py 모듈도 이용하려면

__init__파일에 다음과 같이 추가로 작성해주면 된다.

 

__all__ = ["vietnam", "thai"]

두개 이상의 모듈을 import *로 불러오려면, "파일명"을 ,로 구분해주고, 대괄호를 쳐줘야한다. (리스트의 의미)

 

 

 

** 참고

현재 폴더와 파일의 위치는 다음과 같다.

 


4. 모듈 직접 실행

 

thai.py 모듈에 다음과 같이 코드를 작성한다.

 

class ThailandPackage:
    def detail(self):
        print("[태국 패키지 3박 5일] 방콕, 파타야 여행 50만원")

if __name__ == "__main__":
    print("thai 모듈을 직접 실행") # 모듈이 직접 실행될때 
    print("이 문장은 모듈을 직접 실행할때만 출력됨")
    trip_to = ThailandPackage()
    trip_to.detail()
else:
    print("thai모듈 외부에서 모듈 호출") # practice.py에서 모듈 가져다 쓸 때

 

if - else 문을 통해 모듈이 직접 실행될때와, 모듈 외부에서 호출로 인해 실행될때를 구분하였다.

 

__name__ 값이 '__main__'이라는 것은 모듈이 직접 실행됨을 의미하므로

if __name__ == __main__ 일때는 직접 모듈이 실행되었다는 의미이다.

또한, ThailandPackage라는 클래스로 trip_to 라는 객체를 찍어내고

def로 정의되어있는 detail함수를 실행하도록 하였다.

 

if __name__ == "__main__" 모듈이  내부에서 직접 실행될때
else 모듈 외부에서 모듈을 호출하여 실행될때

 

 


 

5. 패키지, 모듈 위치

위 예제에서는 전부 우리가 작성중인 파일인 practice.py와 패키지가 같은 경로에 있었다.

 

 

동일한 폴더에 있거나, 파이썬 내 라이브러리가 모여있는 폴더에 있어야

모듈을 import를 통해 사용 가능하다.

 

지금 이것이 어느 위치에 있는지 확인할 수 있는 방법이 있다.

practice.py 파일에 다음과 같이 코드를 작성하면 된다.

 

 

inspect라이브러리random 라이브러리를 import로 불러와 이용한다. (from-import가 아닌 단순 import문)

import inspect
import random

print(inspect.getfile(random))

 

작성하고 난 후, 실행 결과는 다음과 같다.

C:\Python39\lib\random.py
PS C:\Users\USER\Desktop\PythonWorkspace>

현재 파일인 practice.py의 위치를 나타내준다.

(위의 random은 random함수가 있는 라이브러리의 위치이다.)

 

 

print(inspect.getfile(thai))

특정 모듈의 위치를 알고싶다면 random 대신 모듈명을 getfile()안에 넣으면 된다.

c:\Users\USER\Desktop\PythonWorkspace\travel\thai.py

 

 

이제, 라이브러리가 들어있는 폴더의 위치도 알았고, travel 폴더의 위치 (thai.py의 위치)도 알았으니

travel 폴더를 통째로 복사하여 Lib폴더 안에 붙여넣어보자.

 

 

위에서 언급한대로, 동일한 폴더에 있거나, 파이썬 내 라이브러리가 모여있는 폴더에 있어야

모듈을 import를 통해 사용 가능하기 때문에 이 과정을 라이브러리 폴더에 옮겨봄으로써 확인해보는 것이다.

 

원래 있던 travel 폴더의 이름을 임시로 다른것으로 바꿔보고,  practice.py를 다시 실행하기 눌러보면

역시 같은 결과가 나온다.

 

즉, 라이브러리 폴더 안에 들어가있는 travel 폴더가 잘 적용이 된 것이다.