문제해결, 의사코드(슈도코드), 컴프리헨션(comprehension), 예외 처리
오늘도 역시 개념 자체를 많이 배운다니보단 여러 상황에 대해 코드를 적고 돌려보는 시간이 많았다. 이번 섹션은 계속 이러려나보다.
기억하자!!
- section5 전체의 최종목적은 자료구조와 알고리즘을 이해하며 프로그래밍하는 것이다.
- section5의 핵심 키워드 : 문제해결과 컴퓨팅 사고력
list = [원소, 원소, 원소 ..]
max_num = 0 (리스트 원소 하나식 꺼내서 얘랑 비교하고 크면 이 변수값을 바꾸자)
i = 0 (인덱스)
while 반복문 i가 리스트 전체 길이보다 작으면 계속 반복:
if 리스트 i번째 원소가 max_num보다 크니?:
max_num = list[i] # 그럼 갱신해.
i += 1 (i 하나 더해)
else: # 아님 갱신하지말고 넘어가
i +=1 (i 하나 더해서 다음 원소도 보자)
# List Comprehension
[반복실행문 for 반복변수 in 반복범위]
[반복실행문 for 반복변수 in 반복범위 if문]
# Set Comprehension
{반복실행문 for 반복변수 in 반복범위}
{반복실행문 for 반복변수 in 반복범위 if문}
# Dictionary Comprehension
{키:밸류 for 반복변수 in 반복범위}
{키:밸류 for 반복변수 in 반복범위 if문}
--
# 이중 for문
[반복실행문 for 반복변수 in 반복범위 for 반복변수 in 반복범위]
[반복실행문(if문 통과시) if 조건 else 반복실행문(else문 통과시) for 반복변수 in 반복범위]
가독성
측면이다. 중첩이 한 번이라도 이루어지면 가독성이 팍! 떨어지기게 된다. 그래서 컴프리헨션은 실무에서 아주 기본적인 위 형태 정도로만 쓴다고 한다.
- 일반적으로 for loop보다 리스트 컴프리헨션이 속도가 더 빠르다고 들었는데, 오늘 노트에서 컴프리헨션에 대해 ‘조건문에 따라 메모리에 영향을 줄 수 있다'고 나와있더라고요. 그럼에도 속도 하나만 봤을 때는 조건문이 복잡해져도 for loop보다 일반적으로 빠른 것이 맞나요? 조건이 복잡해서 가독성을 좀 포기해도 속도가 더 중요한 경우엔 컴프리헨션을 선택할 수도 있나 해서요.
- 협업할 때 가독성이 너무 중요하기 때문에 실무에서 이중포문 이상은 컴프리헨션을 거의 쓰지 않는다고 함. 일반적으론 컴프리헨션이 for loop에 비해 빠른건 맞는게, 저울질을 해봤을 때, 우선순위를 보았을 땐 가독성을 더 높이는게 맞다고 함.
코드를 짜다보면 수많은 변수를 정의하고 가져다 쓰고 하게 되는데, 그때 아래 개념을 알아두면 가독성, side-effect 방지 등 여러모로 이득을 볼 수 있을 것 같다.
지역변수
: 해당 변수가 포함된 함수 안에서만 사용 가능.일반 전역변수
: 하나의 파이썬 파일 전체에서 값을 읽을 수 있다. 되도록이면 이 값을 수정하지는 않고 쓴다고 함. global 전역변수
: 일반 전역 변수와 다른 건 변수가 생성되는 시점! (함수 내에서 선언되는 걸로 생각해도 될듯..?)except
처리하는 것을 남용하지 말고 신중히 사용하라는 말을 자주 들었다. 나중에 디버깅하기도 힘들다고.근데 이런 식의 구문은 처음봤다.
for i in range(3):
print('loop : ', i)
else:
print('break가 실행되지 않았습니다.')
'''
[출력 결과]
loop : 0
loop : 1
loop : 2
break가 실행되지 않았습니다.
'''
print('loop : ', i)
뒤에 break
를 적어주면 출력은 loop : 0
만 되고 끝난다. 아래 구문에서 나는 pass
를 선호해왔는데, continue
를 쓸 수도 있다. 해당 조건은 건너뛰고 다시 반복문을 수행한다는 거다.
# 오이를 싫어하는 사람의 김밥
bucket = ["햄", "계란", "참치","당근", "우엉", "오이", "단무지"]
gimbab = list()
for ingredient in bucket:
if ingredient == "오이":
continue
else:
gimbab.append(ingredient)
print(gimbab)
# ['햄', '계란', '참치', '당근', '우엉', '단무지']
try ~ except ~ else
: 참고로 마지막에 finally
를 쓰면 무조건 실행된다. 아래 코드도 내가 자주 짜본 내용은 아니니 잘 기억해두면 좋을 듯.for ~ else
때 봤던 것처럼 else문은 try문이 실행되면 그 다음에 작동한다. 뒤에 finally
는 else 다음에 무조건 작동된다는 거고. def disneyland():
try:
age = int(input("나이를 입력해주세요: "))
except ValueError as e:
print("숫자로 나이를 입력해주세요.")
print(e)
else:
# 3세 미만은 공짜
if age < 3:
fee = 0
# 3세~9세: 50,000
elif age >= 3 and age < 10:
fee = 50000
else:
fee = 100000
return fee
finally:
print("디즈니 랜드에 오신 것을 환영합니다~!")
disneyland()
assert 문
: 우리 pytest할 때 자주 봤던 거다. 적재적소에 심어두면 디버깅할 때 유용할 것 같다. assert 조건식, 조건식이 false일 경우 출력 메시지
인 것 기억! AssertionError
"""
아래의 test 딕셔너리를 사용해서 아래처럼 출력되도록 만드시오. 컴프리헨션으로 푸는 문제가 아닙니다!
test = {'A': 5, 1: 'B', 'C': 9, 'D': 6, 5: 'E', 'F': 'G', 3:9}
1) 키는 문자여야 한다.
2) 밸류는 숫자여야 한다.
3) 키가 숫자이고 밸류가 문자인 경우 반대로 값을 넣어준다.
#문제 더 어렵게 하면 숫자를 float 케이스 넣을 수 있음
result = {'A': 5, 'B': 1, 'C': 9, 'D': 6, 'E': 5}
"""
test = {'A': 5, 1: 'B', 'C': 9, 'D': 6, 5: 'E', 'F': 'G', 3:9}
result = {}
for i in range(len(test)):
if type(list(test.keys())[i]) == str and type(list(test.values())[i]) == int:
result[list(test.keys())[i]] = list(test.values())[i]
elif type(list(test.keys())[i]) == int and type(list(test.values())[i]) == str:
result[list(test.values())[i]] = list(test.keys())[i]
else:
pass
result
isintance()
를 이용하는 방법도 있다고 함.# 위 문제는 이렇게도 할 수 있다고 함!
test = {'A': 5, 1: 'B', 'C': 9, 'D': 6, 5: 'E', 'F': 'G', 3:9}
result = dict()
for a, b in test.items():
if type(a) != type(b):
if isinstance(b, str):
result[b] = a
else:
result[a] = b
print(result)
'3':9
식으로 되어있으면 위 함수로는 못 제낀다! 그럴 땐 try except
문으로 int 변환시 에러가 나면 ~~ 아니면 ~~ 식으로 구성하면 된다. 오늘은 아래 과제를 했다.
[part1 - 컴프리헨션]
"""
요구사항:
리스트 컴프리헨션 개념을 적용하여 '1~100까지 7과 5의 공배수' 를 구하는 코드를 작성하세요.
아래 예시입력값과 출력값을 참조하며 문제를 해결해봅니다.
입력값:
없음
출력값:
[35, 70]
"""
def part1():
res = [i for i in range(1,101) if i % 7 == 0 and i % 5 ==0]
return res
'''
[기록] - list comprehension을 안 쓰면 이렇게도 할 수 있다!
def part1():
res = []
i = 1
while i <= 100:
if i % 7 == 0 and i % 5 ==0:
res.append(i)
i +=1
else:
i +=1
return res
'''
[part2]
"""
'리스트의 값 중 최댓값'을 구하도록 코드를 구현하세요.
파이썬의 내장함수를 사용하지 않고, 반복문과 조건문을 활용합니다.
아래 예시입력값과 출력값을 참조하며 문제를 해결해봅니다.
입력값:
[4, 8, 5, 11, 7, 2]
출력값:
11
"""
def part2(num):
max_num = 0
i = 0
while i < len(num): # 그냥 for문 써도 똑같음 => 'for i in range(len(ls)):'
if num[i] > max_num:
max_num = num[i]
i += 1
else: i += 1
return max_num
'''
[기록]
# 기본 아이디어 == 그냥 하나씩 꺼내서 비교하자.
list = [원소, 원소, 원소 ..]
max_num = 0 # 리스트 원소 하나식 꺼내서 얘랑 비교하고 크면 이 변수값을 바꾸자.
i = 0 # 인덱스
while i < len(list): # 그냥 for 문
if list[i] > max_num: # 꺼내온 값이 max_num 보다 높니?
max_num = list[i] # 그럼 갱신해.
i += 1
else: # 아님 갱신하지말고 넘어가
i +=1
이런 식으로 해보면 될듯?
'''
[part3]
"""
-1부터 1이상의 입력받은 숫자까지 모든 숫자에 대해 소수가 몇 개 있는지 반환하세요.
-0이하의 경우 ValueError를 발생시켜 주세요.
"""
def part3(N):
if N>1:
pn_list = [] # 소수를 넣어줄 리스트
ls = [i for i in range(2, N+1)] # 2부터 N까지의 숫자가 들어간 리스트
for i in range(len(ls)): # ls에서 하나씩 꺼내서 각 원소별로 그게 소수인지 아닌지 볼 것이다.
num = ls[i]
ls2 = [a for a in range(2, num+1)] # 뽑은 원소까지의 리스트
count = 0 # 아래 for loop 돌고 난 후 count = 1이어야 소수다.
for n in ls2:
if num % n == 0: # num을 또 ls2에서 뽑은 원소로 나눌 때 나머지가 0인 경우 카운트.
count += 1
else: pass
if count == 1:
pn_list.append(n)
else: pass
else: raise ValueError
return len(pn_list)
'''
[기록]
- '소수'가 뭔지에 대한 정의부터 내려야 함: '1과 자기 자신 외의 약수를 가지지 않는 1보다 큰 자연수'
=> 이걸 어떻게 코드로 표현할 수 있을까?
=> 일단 짝수는 2 빼고는 전부 소수 아님. (= 2로 나눠서 나머지 0이면 날리면 됨.)
=> 일의 자리 수에 이렇게 규칙만들기 거슬리는 애들 있으니 십의자리부터 고려하고 일의자리 소수는 아예 고정해두자.
=> 홀수는 구구단의 홀수단 3, 5, 7, 9로 나누어 나머지가 0이면 다 날리면 될 듯?
def part3(N):
if N >=10:
ls = [2,3,5,7] # 소수 담을 공간. 10개 이상인 경우 일의 자리는 기본으로 담기도록.
for i in range(2,N+1):
if i % 2 != 0 and i % 3 != 0 and i % 5 != 0 and i % 7 != 0 and i % 9 != 0:
ls.append(i)
else: pass
num_pn = len(ls)
else: # 좀 더 간단히 할 방법은 없을까..?
if N >= 7:
num_pn = 4
elif N >= 5:
num_pn = 3
elif N >= 3:
num_pn = 2
elif N >=2:
num_pn = 1
else: raise ValueError
return num_pn
=> 음.. 아니네. 위같이 하면 100까지는 되는데 그 이상의 수는 예를 들면 11*11 = 121도 소수로 잡히는 문제가 있다.
- 아예 그냥 '소수' 원래 정의대로 돌아가서 해보자.
=> 2부터 자기 숫자까지 리스트 만들고 하나씩 뽑아서 자기 자신에 나눠보고 나머지가 0이면 카운트 +1,
=> 그리고 마지막에 카운트가 2이면 소수로 추가하는 식으로 하자.
'''
ls2
) range
로 하던데 그게 더 깔끔한 것 같다. 똑같은 기능인데 이렇게 코드가 간단해진다.def part3(N):
if N <= 0:
raise ValueError
n = 0
for i in range(2, N+1):
k = 0
for j in range(2, i):
if i % j == 0:
k += 1
break
if k == 0:
n += 1
return n
Footer