1. 연령별 BMI 지수에 따른 위험도 출력하는 프로그램 작성
BMI 나이 |
~ 21 | 22 ~ |
~ 44 | 낮음 | 중간 |
45 ~ | 중간 | 높음 |
age = int(input("나이를 입력하세요 : "))
bmi = int(input("BMI 지수를 입력하세요 : "))
if age < 45 and bmi < 22 :
print("위험도 : 낮음")
elif age < 45 and bmi >= 22 :
print("위험도 : 중간")
elif age >= 45 and bmi < 22 :
print("위험도 : 중간")
elif age >= 45 and bmi >= 22:
print("위험도 : 높음")
- if - elif 문을 사용해 모든 경우의 수를 조건문에 넣어 원하는 출력값을 정한다.
마지막 elif는 else 문으로 바꿔 사용하면 위 if - elif 문의 모든 조건식이 거짓이면 실행할 수 있고, 위 코드와 같은 출력을 받을 수 있다. 코드가 간결해지고 if 조건문의 연산을 한 번 줄일 수 있는 장점이 있다.
그러나 else를 사용하면 else 뒤에 조건문이 들어가지 않기 때문에 가독성이 떨어질 수 있다. 그래서 가독성과 연산 과정 중에 무엇이 더 좋을지는 상황에 맞춰 선택해야 한다.
위 코드를 평소 일상생활에서 사용하듯이 가독성을 높여 바꿔볼 수 있다.
age = int(input("나이를 입력하세요 : "))
bmi = int(input("BMI 지수를 입력하세요 : "))
young = age < 45
old = not young
slim = bmi < 22
fat = not slim
if young and slim :
print("위험도 : 낮음")
elif young and fat :
print("위험도 : 중간")
elif old and slim :
print("위험도 : 중간")
elif old and fat :
print("위험도 : 높음")
if 문 조건문을 변수에 넣어 주면 가독성을 올릴 수 있다.
조건문 age < 45 and bmi < 22와 young and slim을 비교해 보면 알기 쉽다. young 하고 slim 하면 이라고만 해도 일상생활에서 사용하는 것과 비슷하기 때문에 파악하기 쉽다.
2. 세 개의 변수 x, y, z 중 가장 큰 수를 출력하는 프로그램(단, 내장 함수를 이용하지 않고 작성)
- 내장 함수인 max() 함수를 사용하면 가장 큰 수를 간단하게 구할 수 있다.
a = int(input("첫 번째 숫자 : "))
b = int(input("두 번째 숫자 : "))
c = int(input("세 번째 숫자 : "))
if a > b and a > c :
x = a
elif b > a and b > c :
x = b
else :
x = c
print(f"가장 큰 수는 {x}입니다.")
- 내장 함수 max()를 사용하지 못하므로 if 문으로 해결할 수 있다.
- 각각의 변수를 다른 변수들보다 큰지를 비교해 크다면 그 변수가 가장 큰 값이라는 것을 알 수 있다.
else 문을 사용해 if문의 연산을 한 번 줄였다. 1번 실습에서 말했듯이 가독성도 중요하게 생각해야 하는데, else 문 전에 나온 if 조건문들이 같은 형태를 가지고 있고 다음 변수로만 바꿔서 조건문을 수행하기 때문에 가독성이 떨어지지 않을 것이라 생각해 연산을 줄이는 방식을 선택했다.
3. 세 개의 변수 x, y, z를 조사해서 가장 큰 홀수를 출력하는 프로그램을 작성(단, 이 중에 홀수가 없다면 셋 중에 가장 작은 값을 출력)
- 짝수, 홀수 판단하는 코드
- 큰 수, 작은 수를 출력하는 함수
1) 첫 번째 방법
x = int(input("숫자 입력 : "))
y = int(input("숫자 입력 : "))
z = int(input("숫자 입력 : "))
odd = [] # 입력 받은 수 중 홀수를 저장하기 위한 리스트
if x%2 != 0 : # x를 2로 나눈 나머지가 0이 아니면 odd 리스트 마지막에 x를 추가
odd.append(x)
if y%2 !=0 : # y를 2로 나눈 나머지가 0이 아니면 odd 리스트 마지막에 y를 추가
odd.append(y)
if z%2 != 0 : # z를 2로 나눈 나머지가 0이 아니면 odd 리스트 마지막에 z를 추가
odd.append(z)
if not odd : # if문은 조건식이 참이어야 실행
print(f"홀수 없음. 가장 작은 수 {min(x, y, z)}")
else : # if가 false라면 실행
print(f"홀수 중 가장 큰 수 {max(odd)}")
- odd = [] 리스트를 만드는 것이 중요
홀수는 2로 나눈 나머지가 0이 아니면 홀수를 쉽게 찾을 수 있다. 다음은 찾은 홀수를 어떻게 활용할 수 있는지를 생각해야 한다.
처음에는 찾은 홀수를 어떻게 활용할 수 있을지 생각을 못했지만, 찾은 홀수를 새로운 리스트에 담으면 된다는 것을 알게 됐다. 이렇게 하게 되면 홀수만 들어 있는 리스트가 만들어지기 때문에 가장 큰 홀수를 찾기 쉬워진다.
not 연산자는 조건문이 거짓이면 참이 되기 때문에 odd 리스트에 홀수가 없으면 False가 반환되지만, not 연산자로 인해 참이 되어 if 문이 수행 된다.
다른 방법도 알아본다.
2) 두 번째 방법
a = int(input('첫 번째 수: '))
b = int(input('두 번째 수: '))
c = int(input('세 번째 수: '))
ans = min(a, b, c)
if a % 2 != 0:
ans = a
if b % 2 != 0 and b > ans:
ans = b
if c % 2 != 0 and c > ans:
ans = c
print(ans)
- 이 방법은 변수가 늘어나면 if 문의 코드가 늘어나야 하기 때문에 좋지 않다.
3) 세 번째 방법
a = int(input('첫 번째 수: '))
b = int(input('두 번째 수: '))
c = int(input('세 번째 수: '))
numbers = [a, b, c]
numbers.sort(reverse = True)
ams = 0
for no in numbers :
if no % 2 != 0 :
ams = no
break
if ams == 0 :
ams = min(numbers)
print(ams)
- sort() 함수는 오름차순으로 정렬해주는 함수, reverse 옵션을 주면 반대로 바꾸는 것으로 내림차순으로 된다.
numbers 리스트를 내림차순으로 바꾸는 이유는 가장 큰 수를 앞으로 위치시키기 위함이다.
인덱스 0번에 있는 수가 가장 큰 홀수라면 그것만 가져오면 더 이상 비교할 필요가 없기 때문이다. 하지만 가장 작은 수가 홀수라면 3번의 조건문이 수행된다.
홀수가 없어서 ams가 0이면 numbers 리스트에서 가장 작은 값을 가져오면 된다.
4) 네 번째 방법
a = int(input('첫 번째 수: '))
b = int(input('두 번째 수: '))
c = int(input('세 번째 수: '))
numbers = [a, b, c]
odd_numbers = [no for no in numbers if no %2 != 0]
if odd_numbers :
print(max(odd_numbers))
else :
print(min(numbers))
- 리스트 컴프리헨션을 사용한 방법
numbers의 요소값을 no에 대입해 2로 나눈 나머지가 0이 아니면 odd_numbers 리스트에 저장한다. 위 방법들과 같은 같지만 리스트 컴프리헨션을 사용했다.
5) 다섯 번째 방법
a = int(input('첫 번째 수: '))
b = int(input('두 번째 수: '))
c = int(input('세 번째 수: '))
numbers = [a, b, c]
def odd(no) :
if no % 2 != 0 :
return no
odd_numbers = list(filter(odd, numbers))
if odd_numbers :
print(max(odd_numbers))
else :
print(min(numbers))
- filter() 함수를 사용한 방법
filter() 함수는 함수와 반복 가능한 데이터를 받아 반복 가능한 데이터를 함수에 적용해 참인 것만 묶어서 리턴하기 때문에 홀수만 odd_numbers에 받을 수 있다.
4. 몸무게 80 이상이면 비만, 아니면 정상을 출력하는 리스트를 작성
출력 예시
[20, 70, 87, 99, 82, 60]
['정상', '정상', '비만', '비만', '비만', '정상']
1) append() 함수 사용
- 자료형 2에서 공부한 append(a)는 a를 리스트의 맨 마지막에 요소를 추가하는 함수
- 요소는 모든 자료형이 들어갈 수 있다.
weights = [20, 70, 87, 99, 82, 60] # 몸무게 정의
results = [] # '비만', '정상'을 받기 위한 빈 리스트
for w in weights: # 몸무게 리스트의 요소를 하나씩 w에 대입
if w >= 80: # 만약 80과 같거나 크다면
results.append('비만') # '비만' 추가
else: # 그렇지 않으면
results.append('정상') # '정상' 추가
print(weights) # 몸무게 출력
print(results) # 결과 출력
- 출력 : [20, 70, 87, 99, 82, 60]
- 출력 : ['정상', '정상', '비만', '비만', '비만', '정상']
C언어와 Java의 for 문과 Python의 for 문이 달라서 처음에는 너무 헷갈린다.
C언어와 Java의 for 문은 범위지정부터 몇 번 반복하는지 적어야 한다. 그러나 Python은 그런 문장이 없어서 반복이 범위가 어떻게 되는지, 몇 번 되는지 한 번에 파악하기 힘들다.
Python의 for 문에서 for 다음에 나오는 'w'를 fot 문 밖에서 만드는 변수와 같은 것이라고 생각하면 이해하기 쉽다.
in은 영어 뜻대로 ~안에라는 것이고, 'weights'는 위에서 정의한 몸무게의 리스트다.
그래서 'weights' 리스트 안에서 처음 나오는 요소값을 w 변수에 대입한다. 여기서 반복 횟수와 범위가 정해진다.
- 리스트의 길이 - 반복 횟수
- 리스트의 요소값 - 범위
- 인덱스[0]부터 차례대로 대입
이후 for 문의 수행된다. 천천히 순서대로 따라가다 보면 다른 언어와 다른 for 문을 쉽게 이해할 수 있다.
2) map() 함수 사용
- 조건문, 반복문에서 공부한 map(f, iteralbe)은 함수(f)와 반복할 수 있는 데이터를 입력받아 각 요소에 함수 f를 적용한 결과를 리턴하는 함수
weights = [20, 70, 87, 99, 82, 60] # 몸무게 정의
def checkWeights(w): # 몸무게 확인하는 함수
if w >= 80: return '비만'
else: return '정상'
results = list(map(checkWeights, weights)) # map() 사용
print(weights)
print(results)
- map() 함수는 함수를 받아야 하기 때문에 함수를 정의해 주어야 한다.
- map() 함수에서 checkweights 함수와 weights 리스트를 받고 그 결과를 list로 형변환하여 results에 저장한다.
- map() 함수는 map 객체를 리턴하기 때문에 list로 형변환한다.
3) 위 실습의 출력을 몸무게 : 정상여부 형식으로 수정
(1) range(len(리스트)) 함수 이용
weights = [20, 70, 87, 99, 82, 60]
results = ["정상" if weight < 80 else "비만" for weight in weights]
for i in range(len(weights)):
print(f"{weights[i]} : {results[i]}")
출력
20 : 정상
70 : 정상
87 : 비만
99 : 비만
82 : 비만
60 : 정상
- 리스트 컴프리헨션(List Comprehension)을 사용해 리스트 안에 if 문과 for 문 작성
- len(weights) = 6이고, range(6)되므로 0부터 5까지 입력
중첩된 함수를 하나씩 풀어 나가면서 범위가 어디까지인지 알아야 한다.
(2) enumerate() 함수 이용
- 조건문에서 공부한 함수
- enumerate(리스트)는 리스트의 인덱스와 값을 튜플로 만들고 리스트에 넣어 반환
weights = [20, 70, 87, 99, 82, 60]
results = ["정상" if weight < 80 else "비만" for weight in weights]
for index, weight in enumerate(weights):
print(f"{weight} : {results[index]}")
- results는 리스트 컴프리헨션을 사용
- reuslts에는 renge(len(리스트) 방법에서와 같은 값
- enumerate(weights)에서 인덱스와 요소값을 반환 해서 각각 인덱스와, weight에 대입
- enumerate에서 받아온 인덱스는 results 리스트에 활용해 results 인덱스를 불러 요소값을 반환
enumerate() 함수의 응용을 볼 수 있다. weights 리스트의 인덱스를 받아 왔지만 다른 리스트에 사용함으로써 다른 리스트의 요소값을 받아 올 수 있다.
(3) zip 함수 이용
- zip(반복_가능한_데이터)은 동일한 개수로 이루어진 데이터들을 묶어 각 인덱스의 값을 튜플로 리턴하는 함수
- 튜플로 반환하기 때문에 리스트로 변환하려면 list() 함수를 사용해 형변환
- zip() 함수는 리스트의 길이가 다르면 짧은 리스트의 길이에 맞춰 리턴하고 긴 리스트의 나머지 요소는 무시
weights = [20, 70, 87, 99, 82, 60]
results = ["정상" if weight < 80 else "비만" for weight in weights]
for weight, result in zip(weights, results):
print(f"{weight} : {result}")
- zip(weights, results)은 두 리스트를 묶어 각 인덱스에 있는 값을 리턴
위 enumerate() 함수보다 이해하기는 쉬운 방법이다. 두 리스트의 동일한 인덱스의 값을 리턴해 각 변수에 넣어 주기 때문에 좀 더 쉬운 방법이다. 하지만 zip() 함수를 알지 못하면 생각조차 할 수 없기 때문에 자신의 방법으로 실습을 해보고 다른 방법이 있는지 다른 함수로 같은 출력을 할 수 있는지 생각해 보는 시간이 필요하다.
5. 숫자 맞추기
아래 요구사항을 만족하는 프로그램 작성
- 프로그램에서 생성한 임의의 난수를 맞히는 게임
- 사용자가 숫자를 입력하면 메시지 출력
- 생성한 숫자보다 크면 '크다'
- 생성한 숫자보다 작으면 '작다'
- 생성한 숫자와 입련한 숫자가 일치히면 '00번 만에 맞췄습니다.'
- 사용자가 숫자를 입력하는 기회는 10번으로 제한
- 남은 기회를 출력
- 모든 기회가 사용되면 프로그램 종료
import random
t = int(random.random() * 100)
count = 0
print('숫자 맞추기 게임 시작')
while True :
try:
num = int(input(f"1~99 사이의 숫자 입력 (남은 기회 : {10 - count}) : "))
except ValueError:
print("숫자를 입력해야 합니다.")
continue
if num > 99 :
print('범위를 다시 확인하세요')
continue
count += 1
if num == t :
print(f"정답 {count}번 만에 맞춤")
break
elif num < t :
print("입력한 숫자가 정답보다 작음")
else :
print("입력한 숫자가 정답보다 큼")
if count == 10 :
print(f"모든 기회 소진. 정답 : {t}")
break
- try-except 문은 예외처리 하는 문법이다. 이 구문은 뒤에서 공부할 내용이다.
- try-except 문을 사용하지 않으면 숫자가 아닌 다른 데이터가 입력되면 오류가 나서 프로그램이 비정상적으로 종료될 수 있다.
난수를 활용하기 위해 random 모듈을 import로 가져와 사용한다.
while 문은 무한 루프를 돌고 try-except로 숫자가 아닌 데이터를 예외처리 해 준다.
원하는 범위를 설정해 주고 범위를 벗어난다면 continue로 while 문의 처음으로 돌아간다.
위 예외처리와 범위를 만족한다면 사용자의 횟수를 1 올리고 번호가 맞는지 확인하는 if 문이 실행된다.
사용자의 횟수가 10이라면 정답을 출력하고 프로그램이 종료된다.
대략적으로 위와 같은 순서로 프로그램이 실행된다.
처음에는 try-except 문과 범위 설정을 생각하지 못할 수 있다. try-except 문은 아직 공부하지 않은 문법이기도 하다.
예외처리와 범위 설정을 하지 않고 입력만 받고 사용자의 입력과 난수가 맞는지 확인해도 프로그램은 잘 실행된다.
하지만 사용자의 입력을 검증하지 않으면 원하는 대로 실행되지 않고 비정상적으로 종료되거나 보안에 취약할 수 있다. 사용자의 입력을 받을 때는 사용자의 입력을 검증해야 작성자가 원하는 대로 실행할 수 있다.
범위를 설정하지 않으면 질문에서 나온 1~99 범위를 벗어난 숫자도 입력이 가능하기 때문에 질문에 맞지 않다. 범위를 설정하지 않아도 프로그램은 실행지만 작성자가 원하는 대로 실행을 하기 위해서는 범위를 설정해 쥐는 것이 좋다. 난수가 100 미만이므로 난수의 범위만큼 사용자의 입력의 범위를 제한하는 것이 좋다.
6. 행맨
아래 요구사항을 만족하는 프로그램 작성
- 사용자로부터 영어 문장을 입력받음
- 입력받은 문장을 구성하고 있는 임의의 단어를 하나 추출해서, 해당 단어를 맞히는 게임
- 단어의 길이만큼 "_"를 출력
- 사용자가 알파벳을 입력하면 해당 위치에 알파벳을 출력
- 단어를 맞추는 횟수는 10번으로 제한
- 주어진 횟수 안에 단어를 맞추면 단어와 시도 횟수를 출력
import re
import random
#words = input('여러 단어로 구성된 문장을 입력하세요. ')
words = "This is an optional feature. You can study at W3Schools without using My Learning."
print(f"입력 : {words}")
# 문장부호를 제거 ! " # $ % & ' ( ) * + , - . / : ; < = > ? @ [ ] ^ _ ` { | } ~ \
words = re.sub(r'[!"#$%&\'()*+,-./:;<=>?@\[\]^_\`{|}~\\\\]', '', words)
# 공백문자를 기준으로 단어를 분리
words = words.split()
# 임의의 단어를 추출
rand_word = list(words[random.randrange(len(words))])
# 화면에 출력할 내용
disp_word = list('_' * len(rand_word))
print(f'힌트 : {''.join(disp_word)}')
try_count = 0
while True:
try_count += 1
alpha = input(f'{try_count} 시도 > 영어 단어를 구성하는 알파벳을 입력하세요. ')
for i, a in enumerate(rand_word):
if alpha == a:
disp_word[i] = alpha
print(f'힌트 >>> {''.join(disp_word)}')
if disp_word.count('_') == 0:
print(f'정답 "{''.join(rand_word)}"를 {try_count}번 만에 맞췄습니다.')
break
elif try_count >= 10:
print(f'10번에 기회가 모두 끝났습니다. 정답은 "{''.join(rand_word)}" 입니다.')
break
- re는 정규 표현식을 사용하기 위한 모듈
- 정규 표현식은 복잡한 문자열을 처리할 때 사용하는 기법
- re.sub는 대체할 문자열 패턴, 대체될 문자열, 대체를 수행할 대상 문자열 순서로 옵션을 받는다.
'SK Shieldus Rookies 19th > 인프라 활용을 위한 파이썬' 카테고리의 다른 글
[SK shieldus Rookies 19기][Python] - 실습 2 (0) | 2024.03.17 |
---|---|
[SK shieldus Rookies 19기][Python] - 함수, 파일 (1) | 2024.03.17 |
[SK shieldus Rookies 19기][Python] - 조건문, 반복문 (2) | 2024.03.14 |
[SK shieldus Rookies 19기][Python] - 자료형 4 (0) | 2024.03.14 |
[SK shieldus Rookies 19기][Python] - 자료형 3 (1) | 2024.03.13 |
댓글