Python #2
4차인재 양성사업
과학기술 빅데이터 분석가 과정 - 4주
김정훈 강사님
Day_02_01_Loop
이 섹션은 if, while, for문의 기초내용을 다루고 있다.
if문
a = 7
if a % 2 :
print('홀수')
else :
print('짝수')
a = input('number : ')
print('result : ', a)
문제 1. 앞에서 입력 받은 변수 a의 값이 음수인지 양수인지 0인지 알려주세요
#1
if a > 0 :
print('양수')
else :
if a < 0:
print('음수')
else :
print('0')
#2
if a > 0 :
print('양수')
elif a < 0:
print('음수')
else :
print('0')
#2의 elif는 else 안의 if 문을 하위로 넣지 않고 같은 순위로 당겨주기 위한 문법이다.
하위가 늘어나면 지저분해지고 가독성이 떨어지니까. 기능은 동일하다. 그냥 C언어같은 다른데의 else if 문이다.
문제 2. if문을 사용해서 a의 숫자만큼 'hello'를 출력하세요 (0 <= a <= 3)
미리 말하자면 바로 밑의 솔루션은 잘못된 것이다.
굳이 if 안에 *a 쓸 이유가 없다 싶었는데, 문제 오류로 *a를 쓰지 말란 조건을 나중에 붙이셨다.
#1
a = 0
print('hello' * a)
#2
if 0 < a <= 3 :
print('hello' * a)
elif a == 0 :
print('a is zero')
else :
print('a is not in range')
이 밑부터가 제대로 된 솔루션이다.
if a == 0 :
print(' ')
print('a is zero')
elif a ==1 :
print('hello')
elif a ==2 :
print('hellohello')
elif a ==3 :
print('hellohellohello')
이 문제에 대해선 강사님이 정말 다양한 솔루션을 내놓으셨다.
#강사님 sol.1
a = 1
if a > 0 :
print('hello')
a = a - 1
if a > 0 :
print('hello')
a = a - 1
if a > 0 :
print('hello')
a = a - 1
같은 코드를 복사 붙여넣기 했고 뭘 한다는지를 명백하게 알 수 있다는게 장점인 sol.1
밑의 다른 코드들보다 변수가 작으므로 좋은 코드라고 한다.
성능이 크게 중요한 파이썬이 아닐지라도 변수 차이는 성능과 정확도에 차이가 나기 때문.
#강사님 sol.2
a = 3
i = 0
if i < a :
print('hello')
i += 1
if i < a :
print('hello')
i += 1
if i < a :
print('hello')
i += 1
위의 코드는 a가 3보다 작을 때 불필요한 if문이 두번이나 더 존재한다.
밑의 경우는 결국 하나의 if문 또 그 안에 하나의 if문이므로 하나를 처리하면 되기 때문에 위 보다 효율적이라고 본다.
#강사님 sol.3
a = 3
i = 0
if i < a :
print('hello')
i += 1
if i < a :
print('hello')
i += 1
if i < a :
print('hello')
i += 1
while문
a = 7
i = 0
while i < a :
print('hello')
i += 1
# else :
# print('else')
파이썬에만 while에 else가 존재한다. 다만 열명중 한 명도 모를 정도로 안 쓴다고 하셨다. 초보자 언어라 유도리있는것뿐..
문제 3. 0~99까지 출력하세요
문제 4. 0~99까지 한 줄에 10개씩 출력하세요
i = 0
p = 100
while i < p :
print(i),
if i % 10 == 9 :
print('\n')
i += 1
아래 블록은 둘 이상의 프린트문을 개행 없이 출력하는 방법인데
이때 가상환경을 다운받았던 파이썬 3.6.8버전이 아닌 맥에 기본으로 장착된 python2로 설정하는 바람에 난리가 났던(...)부분이라
그냥 기록만 해두기로..
+ for문과 range 실습에 앞서 시작과 종료에 대한 개념잡은 파트
# print('12', end='**')
# print('34') 개행하지 않고 출력하는 방법이라는데 end가 에러뜬다
i = 0 # 시작
while i < 25 : # 종료
# print(i, end=' ') #python2와 3에 따른 오류로 맥에는 기본적으로 2.7 리눅스환경이 설치되어있기때문에
# 이걸 지울 순 없고 파이챰 가상환경이니까 3을 깔아서 써야함. 업데이트를 권장..
print(i),
# if i == 4 or i == 9 or i == 14 or i == 19 or i == 24
# if i % 10 == 4 or i % 10 == 9
if i % 5 == 4:
print()
i+= 1 # 증감
print() # 줄바꿈
for문과 range의 개념
# 0 1 2 3 4 (0,4,1) 규칙찾기. 0부터 4까지 1 증가
# 1 3 5 7 9 (1,9,2)
# 4 3 2 1 0 (4,0,-1)
# (0, 4, 1)
for i in range(5) : # 시작(0), 종료, 증감(1)
print(i),
print()
for i in range(0, 5) : # 시작, 종료 (증감은 기본값으로 1)
print(i),
print()
for i in range(0, 5, 1) : # 시작, 종료, 증감
print(i),
print()
문제 5. 나머지 2개의 규칙을 for문으로 만드세요
for i in range(1, 11, 2): #(1,9,2)
print(i),
print('')
for i in range(5-1, -1, -1): #(4,-1,-1)
print(i),
print('')
for i in range(1, 10, 2): #(1,9,2)
print(i),
print('')
for i in range(4, -1, -1): #(4,-1,-1)
print(i),
print('')
print('')
문제 6. 아래처럼 출력하세요 (대망의 피라미드문제..!!)
*
**
***
****
# 내 코드
for i in range(4):
for j in range(i+1):
print('*'),
print('')
print('')
# 강사님 코드
for i in range(4):
for j in range(4):
if i >= j:
print('*'),
else:
print('-'),
print('')
print('')
# i\j 0123
# 0 *
# 1 **
# 2 ***
# 3 ****
# 수학 좌표처럼 행과 열의 좌표로 생각하고 대각선의 관계로 생각하면 된다.
# 최종정답코드
for i in range(5):
print('*'*i)
print('')
****
***
**
*
# 강사님코드
for i in range(4-1,-1,-1):
for j in range(4):
if i >= j:
print('*'),
else:
print('-'),
print('')
print('')
# 내부 코드를 바꾸기 보다 환경변수를 바꾸는 편이 훨씬 간단하지만 대부분 생각하지 못한다.
# 모양이 반대가 되면? 대각선이 어떤 모양이냐에 따라 행과 열의 환경변수만 바꾸어주면 되는데..
for i in range(4,0,-1):
print('*'*i)
print('')
*
**
***
****
for i in range(1,5,1):
print(' '*(4-i),end=''),
print('*'*i)
print('')
# end 개행방지가 없으면 ' '가 *의 다음 줄로 출력이 된다
****
***
**
*
for i in range(0,4,1):
print(' '*i, end=''),
print('*'*(4-i))
print('')
Day_02_02_Collection
콜렉션(collection) : 리스트, 튜플, 셋, 딕셔너리 (리스트가 80%). 파이썬에는 배열이 없고, 셋 = 집합인데 거의 쓸 일이 없다.
[] () {} {}
이 섹션에서는 리스트를 주로 다루고 앞에서 배운 loop문도 일부 활용되며, 튜플이 일부 나온다.
딕셔너리는 이 다음 02_03_json에서 다룬다.
list
import random # 난수 생성 모듈. 사용되기 전 회색인 건 정상. 사용 되면 활성화된다.
a = [1,3,5, 'abc']
a.append(11)
print(a)
print(a[0], a[1], a[2])
print(len(a)) # 갯수
위의 a 처럼, 파이썬은 리스트 안에 서로 다른 타입의 데이터를 동시에 넣는게 가능하다.
하지만 다른 유형의 데이터를 저렇게 한번에 넣는 일은 없다고 보면 된다. 집에 못 가기땜에..
append는 리스트에 새로운 데이터를 추가할때 사용한다.
a.append(11) 처럼 append는 위치를 필요로 하는데, 여기서 리스트명인 a가 데이터를 추가할 위치를 의미한다.
len은 쉽게 말하자면 길이를 출력해주는 것이므로 리스트 내 데이터의 갯수를 반환하다고 볼 수 있다.
문제 1. 반복문을 사용해서 리스트의 전체 요소를 출력하세요
i = 0
while i < len(a) :
print(a[i], end=' ')
i += 1
print()
#강사님코드
for i in range(len(a)):
print(a[i], end = ' ')
print()
#강사님코드 - 차이점. 이 코드는 전체를 뽑아내는 것. 위의 것은 일부를 뽑을 때 씀.
for i in a :
print(i, end = ' ')
print()
아래는 10칸짜리 리스트에 1~100사이 숫자 10개를 랜덤하게 채워넣고 프린트하는 코드이다.
numbers = []
for i in range(10):
print(random.randrange(100), end = ' ')
# randrange : range와 사용법 같음.
numbers.append(random.randrange(100)) # 리스트이므로 대괄호 달고 출력된다.
print(numbers)
문제 2. 리스트에서 홀수 개수를 알려주는 함수를 만드세요
numbers.append(random.randrange(100))
def f_odd(a) :
for i in range(len(a)) :
if a[i] % 2 == 1 :
print(a[i], end = ' ')
print(numbers)
f_odd(numbers)
# 교수님 코드
def odd_count(numbers) :
odd = 0
for i in numbers :
if i % 2 :
odd += 1
# ----------------------- #
if i % 2 :
odd += i % 2 # 대신 이 경우는 else가 필요함
else
odd += i % 2
return odd
print('홀수 :', odd_count(numbers))
위의 코드는 if문을 잘못 쓴 예시다.
if,else에 같은 조건문이 들어간다면 if를 쓸 이유가 없다. 즉, 잘못 쓴 경우이다.
두 조건문이 달라야 if문을 쓰는 의미가 있다. 따라서 정답은 아래와 같이 쓰는것이 좀 더 맞다.
def odd_count(numbers) :
odd = 0
for i in numbers :
odd += i % 2
return odd
print('홀수 :', odd_count(numbers))
if문과 else문의 조건문이 같으므로 if문을 써줄 필요가 없는 것이다.
여기서 함수에 받는 매개변수 이름은 numbers가 아니라 다른 것이어도 되는데
강사님 말로는 다르게 하면 오히려 피곤하다고 한다.
아마 나중에 코드를 읽을 때, 외부의 변수 중 어떤 변수를 함수 내로 읽어들어오는지를 판단하기에
두 이름이 같은 편이 읽기 수월하다는 의미가 아닐까 생각한다.
문제 3. 리스트를 거꾸로 출력하는 함수를 만드세요
numbers.append(random.randrange(100))
print(numbers)
def reverse_list(numbers) :
# for i in range (len(numbers)-1, -1, -1) : #len(numbers)에 -1을 안해서 범위에 벗어났었다..!!
# print(numbers[i], end=' ')
# print()
# for i in reversed(numbers) : # reversed라는 뒤집는 파이썬 함수 사용
# print(i, end = ' ')
# print()
for i in reversed(range (len(numbers))) : # 첫번째 것 뒤집
print(numbers[i], end=' ')
print()
reverse_list(numbers)
문제 4. 리스트를 거꾸로 뒤집는 함수를 만드세요
내가 제일 어려워했던 문제다.
리스트 하나 더 만들어서 백업하고 그 잃어버린 값을 넣어주거나 인덱스를 리버스해서 넣겠다는 생각으로 매달렸는데
결국 시간 내에 못 풀었던 흔적이..ㅋㅋㅋ
def reverse_list_1(numbers):
another = []
for i in reversed(numbers):
another.append(i)
# append : 앞에서부터 채워넣음. 그러네 인덱스를 굳이 찾아서 쓸 필요가 없었다..
return another
def reverse_list_2(numbers):
# 0번째 데이터가-> 9번째로, 1->8, 2->7
# 0-> 9-0 , 1-> 9-1, 2-> 9-2
another = [0,0,0,0,0,0,0,0,0,0]
for i in range(len(numbers)):
another[9-i] = numbers[i]
return another
def reverse_list_3(numbers):
# 0번째 데이터가-> 9번째로, 1->8, 2->7
# 0-> 9-0 , 1-> 9-1, 2-> 9-2
another = [0]*len(numbers)
for i in range(len(numbers)):
another[len(numbers)-1-i] = numbers[i]
return another
# 0 3 2 8
# 8 2 3 0
def reverse_list_4(numbers):
numbers[0], numbers[9] = numbers[9], numbers[0]
numbers[1], numbers[8] = numbers[8], numbers[1]
numbers[2], numbers[7] = numbers[7], numbers[2]
numbers[3], numbers[6] = numbers[6], numbers[3]
numbers[4], numbers[5] = numbers[5], numbers[4]
size = len(numbers)
for i in range(size):
numbers[i], numbers[size-1-i] = numbers[size-1-i], numbers[i]
numbers = reverse_list_2(numbers)
print(numbers)
tuple
a = [1,3,5]
b = (1,3,5) # 튜플
a[0] = 99
# b[0] = 99 #error. 읽기전용이라 변경이 되지 않음. 즉 튜플은 상수.
a.append(88)
# b.append(88) #error
print(a,b)
print(b[0],b[len(b)-1]) #접근방식은 동일하다.
결국 잘 안쓴다는 결론이다. 파이썬을 만든 사람이 쓰려고(변경할 수 없다 를 시스템적으로 나타낼때) 만들었다는데..
함수 안에 작은 단위(?)를 묶을때 쓰긴 한다는데 귀찮으니까 그냥 리스트를 쓴다고 한다.
t1 = (1,2)
t2 = 1,2
print(t1, t2)
t2 역시 튜플타입으로 괄호 생략 가능하다. 하지만 첫 날 이렇게 쓰는건 좋지 않다고 설명했다.
t3, t4 = 1, 2
# t3, t4 = 1, 2, 3 #error
print(t3, t4)
첫 줄처럼 좌 우 변수 갯수는 꼭 맞춰주어야 한다. 이 경우엔 int타입.
t3, t4 = t1
print(t3,t4)
이 경우에는 좌 우 변수 갯수가 다른데? 싶지만
이런 다중치환 때, 좌 우 데이터 갯수가 맞지 않을때 튜플이 들어가서 중재한다.
t1 = (1, 2)이기 때문에 결국 좌 우 변수 갯수 두개로 동일한 것이다.
def exchange(x,y) :
return y, x
# return (y,x) #실제로는 튜플로 묶어서 하나를 넘겨주었다고 보는게 맞으나
#우리가 보기에는 두 개를 줬다고 보는게 타당하다
t5 = exchange(12, 34)
print(t5,type(t5))
t6, t7 = exchange(12, 34)
print(t6, t7)
t8, _ = exchange(12, 34) #place holder
print(t8)
튜플을 활용하면 위 exchange 함수에서 보이듯 다중반환이 가능하다.
Day_02_03_json
Dictionary
import json
import requests
a1 = '{"ip": "8.8.8.8"}'
print(a1, type(a1))
a2 = json.loads(a1)
print(a2, type(a2))
print(a2['ip'])
a3 = json.dumps(a2)
print(a3, type(a3))
a1은 딕셔너리의 기본적인 형태이다.
딕셔너리는 "Key"와 "Value"를 기본 한 쌍으로 갖는 자료형이다.
이렇게 key와 value 여러 쌍이 중괄호{}로 묶여있고 쉼표(,)로 구분되어진 자료형으로
리스트나 튜플과는 달리 순차적으로(sequential) 데이터를 찾는게 아니라 key를 검색해 value를 추출할 수 있다는 특징이 있다.
문제 1. 값에 해당하는 데이만 출력하세요
b1 = '''{
"time": "03:53:25 AM",
"milliseconds_since_epoch": 1362196405309,
"date": "03-02-2013"
}'''
print(b1, type(b1))
b2 = json.loads(b1)
print()
print(b2)
print(b2['time'])
print(b2['milliseconds_since_epoch'])
print(b2['date'])
cf. b1에서 작은따옴표를 양쪽에 세 개씩 붙인게 무엇인가 궁금해 구글링하니 주석이라는 말도 있고, 여러줄 문자열이라는 말도 있다.
https://programmers.co.kr/learn/questions/659
하지만 출력이 멀쩡히 되는 것을 보면 여러줄 문자열이라는 말이 맞는 듯하다.
문제 2. 몇 시인지 알려주세요 (네이버 활용)
# recvd = requests.get('http://www.naver.com')
def what_time() :
recvd = requests.get('http://date.jsontest.com')
datetime = json.loads(recvd.text)
print('time : ', datetime['time'])
print(recvd) # Response [200]
print(recvd.text)
맨 처음 코드를 짤 때 datetime에 json.loads(recvd)로 써 넣어서 제대로 출력이 안 되었었다.
print(recvd)로 확인해보면 recvd는 내가 생각한대로 텍스트들이 불려오는 게 아니라 Response[200], 즉 HTTP 응답상태코드가 반환된다.
따라서 원하는대로 내용을 가져오려면 recvd.text로 가져와야 dictionary 형태로 불러올 수가 있다.
cf. Response [200] : 네이버로부터 데이터를 잘 가져왔다는 뜻이다. 200은 Okay라는 뜻. Not Found 404처럼
Day_02_04_HW
과제
url = 'http://www.kma.go.kr/DFSROOT/POINT/DATA/top.json.txt'
recvd = requests.get(url)
# print(recvd.text) #한글이 깨짐
data = recvd.content.decode('utf-8')
print(data)
# 리스트타입의 데이터 출력됨
# [{"code":"11","value":"서울특별시"},
# {"code":"26","value":"부산광역시"},
# {"code":"27","value":"대구광역시"},
# {"code":"28","value":"인천광역시"},
# {"code":"29","value":"광주광역시"},
# {"code":"30","value":"대전광역시"},
# {"code":"31","value":"울산광역시"},
# {"code":"41","value":"경기도"},
# {"code":"42","value":"강원도"},
# {"code":"43","value":"충청북도"},
# {"code":"44","value":"충청남도"},
# {"code":"45","value":"전라북도"},
# {"code":"46","value":"전라남도"},
# {"code":"47","value":"경상북도"},
# {"code":"48","value":"경상남도"},
# {"code":"50","value":"제주특별자치도"}]
print('-'*50)
# 과제 1
# 코드 번호와 지역 이름만 깨끗하게 출력하세요 (json)
# 과제 2
# 코드 번호와 지역 이름만 깨끗하게 출력하세요 (re)