우리는 반복문을 배우고 제어문으로 넘어왔다. 제어문이란 "이런 상황의 경우 이렇게 실행하시오"를 알려주는 프로그램의 분기점이다. Python은 if ~ elif ~ else를 통한 제어문을 사용한다. 다음의 예시를 확인해보자

코드 :
score = 50
if(score >=90) :
    print("A학점입니다")
elif(score >= 80) :
    print("B학점입니다.")
elif(score >= 70) :
    print("C학점입니다.")
else :
    print("수업을 겨드랑이로 들었니?")

제어문의 문법은 다음과 같다.

여기서 사용할 주의점은 다음과 같다.

① elif와 else는 if가 있어야만 사용할 수 있다. 단, elif나 if 없이 if로만 구성된 반복문도 허용한다.

② if, elif, else가 하나라도 실행될 경우 아래 내용은 실행되지 않는다.

③ elif는 여러개 사용될 수 있다.

④ else는 모든 if와 elif가 거짓일 때 동작한다.

 

위의 내용의 예시는 다음과 같다.

① elif와 else는 if가 있어야만 사용할 수 있다. 단, elif나 if 없이 if로만 구성된 반복문도 허용한다.
if(a>b) :
	##
elif(b<a) :
	##
else :
	##
    
if(a>b) :
	##

② if, elif, else가 하나라도 실행될 경우 아래 내용은 실행되지 않는다.
a=3
b=5
if(a<b) :
	print("a가 b보다 작습니다")
elif(a>b) :
    print("b가 a보다 작습니다.")
else :
    print("a는 b와 같습니다.")
## 이 제어문은 elif와 else가 실행되지 않는다.

③ elif는 여러개 사용될 수 있다.
if(조건) :
	##
elif(조건2) :
	##
elif(조건3) :
	##
else(조건) :
	##
    
④ else는 모든 if와 elif가 거짓일때 동작한다.
a=3
b=3
if(a<b) :
	print("a가 b보다 작습니다")
elif(a>b) :
    print("b가 a보다 작습니다.")
else :
    print("a는 b와 같습니다.")
  
출력 : 
"a는 b와 같습니다."

 

* 제어문역시 Indent로 블록을 구분한다.

* if문안에 중첩된 if를 쓰는것또한 가능하다.


이번 시간에는 프로그래밍의 꽃인 제어문에 대해서 Pythond은 어떤 제어문을 사용하는지 알아보았다. 다음 시간에는 프로그래밍의 꽃(벌써 3번째 꽃이다. 프로그래밍은 꽃밭이다 아주) 함수에 대해서 알아보도록 하자

우리는 이제 귀찮은 작업을 일일이 타이핑하는 것이 아닌, 반복문이라는 도구로 빠른 퇴근을 도모할 수 있게 되었다. 이번 시간에는 반복문에 대해서 조금 더 깊은 이해를 가질 수 있는 여러 가지 반복문과, 반복문의 제어 등을 알아보자

 


들여 쓰기(Indent)

문득 이런 생각이 들었던 독자도 있을 것이다. "어디까지가 반복문인지 Python이 어떻게 알지?"(이래서 눈치 빠른 녀석들이란...) 사실 다른 프로그래밍 언어는 아래와 같이 중괄호를 통해서 어디까지를 그 지역으로 지정할지를 설정한다. 

for(int i=0 ; i<students.length ;i++) {
    students[i] = students[i].replace("철수","**");
    System.out.println(students[i]);
}
// JAVA언어에서의 for문 이다. 중괄호({})를 통해 어디까지가 for문인지를 지정한다.

다른 언어에서는 가독성을 위해서 들어 쓰기(Indent)를 하지만 Python은 문법적으로 같은 수준으로 Indent 된 것들을  한 지역으로 보고 Indent가 다시 돌아온 순간을 그 지역의 끝으로 인식한다. 다음의 예시를 보도록 하자

코드 : 
for i in range(10) :
    a=i
    print(a)

print("루프 종료")

출력 : 
1
2
3
4
5
6
7
8
9
10
"루프 종료"

for문으로 동작하는 것은 같은 들여 쓰기 수준을 가진 a=i와 print(i)만 이고 제일 아래줄인 print("루프 종료")는 for문으로 반복되지 않는다. 들여 쓰기는 [TAB]으로 입력할 수 있으며, 공백(스페이스) 4칸 또한 들여 쓰기로 인정한다.

 

반복문의 제어

*아래부터는 제어문 강의를 읽고 오면 도움이 많이 된다.*

반복문은 시작되면 끝까지 달리는 핸들이 고장 난 8톤 트럭이 아니다. 반복문이 실행되는 도중에도 반복문의 강제 종료, 다음 루프로의 강제이동 등이 가능하다. 크게 사용하는 반복문의 제어는 break와 continue가 있다.

코드 : 
for i in range(10) :
    a=i
    if(i>5) : 
    	break
    print(a)
        
print("루프 종료")

출력 : 
1
2
3
4
5
"루프 종료"

중간에 if는 조건 제어문인데, 간단하게 i가 5보다 크면 제어블록 안에 있는 break가 동작한다고 생각해주면 된다.

break는 돌고 있는 가장 가까운 루프를 강제 종료시키는 특징이 있다.

코드 : 
for i in range(10) :
    a=i
    if(i<5) : 
    	continue
    print(a)
        
print("루프 종료")

출력 : 
5
6
7
8
9
10
"루프 종료"

cotinue는 돌고 있는 가장 가까운 루프를 다음 루프로 강제 이동한다. 따라서 이 for는 i가 5보다 작을 때 강제로 다음 루프로 이동되어 i가 5보다 같거나 커질 때까지 print(i)는 실행되지 않는다.

 

무한루프(Infinite Loop)

무한루프는 말 그대로 끝나지 않는 루프이다.(컴퓨터 세상에서 만큼은 우리 무한으로 즐겨보자) 

무한루프는 보통 while문으로 걸게 되며, 다음의 코드로 알아보자

코드 : 
while(True) :
    print("무한으로 즐겨요")
        
print("루프 종료")

출력 : 
무한으로 즐겨요
무한으로 즐겨요
무한으로 즐겨요
무한으로 즐겨요
무한으로 즐겨요
...
...

시작하면 멈추지 않는 특성 때문에 보통 위에서 설명한 break와 같이 사용된다.

 

range SLICING

for문의 범위를 지정하는 range는 자료구조의 slicing처럼 slicing이 가능하다. 

코드 : 
for i in range(3,5) :
    print(i)

출력 : 
3
4

코드 :
for i in range(0,10,2) :
	print(i)

출력 : 
0
2
4
6
8

단, 배열의 인덱스를 의미하는 것이 아니기 때문에 음수 인덱스(자료구조에서는 역으로 읽는 인덱스를 의미했다.)는 진짜 음수로 인식한다.

코드 :
for i in range(-1,10,2) :
	print(i)

출력 : 
-1
1
3
5
7
9

이번 시간에는 코드 블록을 나누는 방법(Indent),반복문의 제어, range를 자유자재로 다룰 수 있는 방법을 알아보았다. 사실 for문은 더 실용적인 사용법인 Advanced-for라는 문법이 있다. 다만, 조금 더 어려운 개념(generator, iterator)등이 들어가기에, 포스팅을 계속하며 Advacned-for도 쉽게 이해할 순간이 되는 순간 설명하도록 하겠다. 다음 시간에는 프로그래밍에 꽃(벌써 2번째 꽃이다.) 제어문에 대해서 알아보도록 하자

학생관리 프로그램을 만드는 저번 시간, 여러 자료구조의 힘을 빌려서 우리는 변수를 하나로 지정하는 효율적인 방법을 알았지만, 휴. 이제 퇴근을 해야 되는데 우리나라의 이름 체계가 바뀌는 바람에 "철수"라는 이름의 사용이 금지되었다. 이제 모든 "철수"는 아직 정해지지 않았기 때문에 "**"로 바꾸어야 되는 상황이 왔다. 

 

다행히도 우리의 Python은 문자열에 대해서. replace([기존], [바꿀 문자열])을 제공한다.

>> students[0] = "김철수"
>> students[0] = students[0].replace("철수","**")
// students[0]의 철수를 **로 바꾼다.

>> print(students[0])
"김**"

훌륭한 기능이 주어졌으니, 이제 남은 건 위의 코드를 students의 길이만큼 치는 일이 남아있다.... 무언가 비효율적이다.

다행히도, 우리의 퇴근시간을 앞당겨줄 <반복문>이라는 훌륭한 도구가 있다.

 

 students[0] = "김철수, students[1] = "배철수", students[2] = "윤철수"    ...    students[29] = "남궁 철수"

잘 보면 students의 인덱스가 1씩 늘어남으로 각각의 원소에 접근을 할 수 있는 것을 알고 있다. 

 

 

반복문은 컴퓨터의 특성을 아주 잘 살린 제어블록으로 단순한 작업을 여러번 반복하는 내용을 담고 있다. python에서 사용하는 반복문은 크게 for문과 while문이 있는데, 순서대로 알아보도록 하자


for문의 사용

다음과 같은 예시를 통해서 반복문이 어떻게 사용되는 지 알아보도록 하자

*여기서 students는 길이가 30인 LIST이다.

코드 :
for i in range(len(students)) :
	students[i] = students[i].replace("철수","**")
	print(students[i])
    
    
출력 :
"김**"
"배**"
...
"남궁**"

일단 낯선 코드가 눈에 보인다. for i in range(len(students)) : 란 무엇일까?

for 반복문은 모두 위와 같은 형태를 띈다. 반복자가 0부터 (범위-1)만큼 늘어나며 반복을 하는 것이다.

* 왜 0부터 범위-1 인지는 Python과 친해지기 LIST를 보도록 하자 

* 위와 같은 이유로 [범위] 안에는 무조건적으로 정수(Integer)가 들어가야 한다.

 

첫 번째 반복(루프) 때는 아래와 같은 항목이 실행이 되고, 반복자(i)의 크기가 1이 늘어난다.

student[0] = students[0].replace("철수","")
print(students[0])

이제 i는 1이 되었고 아래와 같은 항목이 실행이 된다.

student[1] = students[1].replace("철수","")
print(students[1])

반복적으로 실행을 하며 i는 3,4,5 ... 28까지 왔고 다음과 같은 마지막 항목이 실행이 되며 for반복문이 종료된다.

student[29] = students[29].replace("철수","")
print(students[29])

 

다음으로는 또 다른 반복문인 while문에 대해서 알아보도록 하자

 

while문의 사용

cnt = 0
while(cnt<30) :
	students[cnt] = students[cnt].replace("철수","**")
    	print(student[cnt])
    	cnt+=1

while은 다음과 같은 문법 형태를 가진다.

조건은 저번 시간에 배웠던 True, False를 반환 가능한 연산자를 활용해도 되고, True나 False 그 자체를 집어넣어도 상관없다. for와 비슷한 형태를 가지지만, 반복자가 없다는 특징이 있다. 이러한 이유로 while 반복문에서 반복자 같은 개념을 사용하려면 직접 반복자 같이 사용할 변수를 지정해야 한다는 특징이 있다.(위 예시문에서는 cnt가 되겠다)

 


이번 시간에는 반복문의 기본인 for와 while에 관하여 이야기를 나누었다. 다음 시간에는 반복문에 대한 깊은 이해를 위해 여러 가지 반복문의 사용과 반복문의 특징과 주의 점등을 알아보도록 하자

Python이 제공하는 강력한 기능 중 하나인 SLICING, 자료구조를 압니다.라고 자신 있게 말한 사람이 SLICING도 모른다고 하면 그것도 참 웃긴 일이다.  Python을 Python 답게 해주는 또 다른 강력한 도구인 SLICING에 대해서 알아보고 자료구조와 어울리는 간단한 내장 함수 또한 알아보도록 하자

 


 

SLICING : 파이선에서 연속적인 객체들의 일부 범위를 선택해서 가져오는 방법

그렇다. 말그대로 자료구조 중 일부를 잘라(SLICE)해서 가져오는 방법이 SLICE이다.

우리를 도와줄 자료구조 my_array를 소개한다.

>> my_array = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 
21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42,
43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 
65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 
87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99]

그렇다 0~99를 가진 LIST이다.

 

SLICING은 3가지만 기억하면 된다. START, END, STEP

① start : 어디서부터 SLICE 할지를 지정하는 인덱스이다.

② end : 어디까지 SLICE할지를 지정하는 인덱스이다.

③ step : 보폭이다. start와 end사이를 얼마나 뛰어서 슬라이스 할지를 의미한다.

 

다음의 예시를 보면서 SLICE와 친숙해져 보도록 하자

>> print(my_array[0:50:2])
[0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38, 40, 42, 44, 46, 48]

>> print(my_array[:30:4])
[0, 4, 8, 12, 16, 20, 24, 28]

>> print(my_array[3::10])
[3, 13, 23, 33, 43, 53, 63, 73, 83, 93]

>> print(my_array[:-50])
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 
25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 
48, 49]

위에서 알 수 있는 SLICING의 규칙은 다음과 같다.

1. 값이 생략되면 start는 0, end는 인덱스의 끝, step은 1을 가진다.

2. 음수는 뒤에서부터 카운트한다.(따라서 배열의 가장 마지막은 -1의 인덱스, 2번째 마지막은 -2의 인덱스 가 된다. 꽤나 자주 사용하는 인덱스이니 알아두기를 바란다.)

 

내장 함수

내장 함수는 파이선에서 기본적으로 제공하는 함수들로 정말 많은 내장 함수들이 있지만, 특히 자료구조와 더욱 어우러 지는(어우러진다. 마치 오리엔탈 샐러드) 내장함수들이 많이 존재한다. 다음과 예시를 보도록 하자

>> my_array = [1,2,3,4,5,6]
>> my_dict = {1:"a",2:"b",3:"c"}
>> my_tuple = (1,2,3)

>> sum(my_array)
21
>> sum(my_dict)
6
>> sum(my_tuple)
6

>> len(my_array)
6
>> len(my_dict)
3
>> len(my_tuple)
3

>> max(my_array)
6
>> max(my_dict)
3
>> max(my_tuple)
3

>> min(my_array)
1
>> min(my_dict)
1
>> min(my_tuple)
1

위에 사용된 함수는 총 4가지가 있다. ① 합연산의 sum, ② 길이를 반환하는 len, ③ 최댓값을 반환하는 max, ④ 최솟값을 반환하는 min 이 4가지만 알아도 간단한 프로그램의 자료구조를 내장 함수 사용하는 데에는 어려움은 없을 것이다.

* dict은 list와의 강제 캐스팅 때에도 보았었지만 기본적인 연산을 적용하는 경우 보통 key를 기준으로 연산이 되는 것을 확인할 수 있다. dict.items()는 이때 사용되는 것이다. 자세한 것은 반복문에서 배우게 될 것이다.


이번 시간에는 간단하게 원하는 부분을 자르는 SLICING과 자료구조와 어우러지는 내장 함수를 몇 가지 살펴보았다. 이제 프로그래밍의 꽃인 반복과 제어 그중에서도 반복에 들어갈 준비가 된 것이다. 설마 벌써 흥미를 잃지는 않았기를 바라면서(필자는 여기서 흥미를 잃었었다.) 필자는 다음 강의에서 여러분을 기다리겠다.

이제 자료구조의 마지막 시간인 TUPLE에 들어왔다. 물론 Python의 고급단계에는 라이브러리에 더 많은 자료형이 존재하지만, TUPLE까지 배우면 어디서 보아뱀 구조는 제가 좀 압니다 할 수 있다.


TUPLE의 정의와 사용

TUPLE은 LIST와 거의 유사하다(아싸 글적을 거 줄었다!) 단 원소의 생성 / 삭제 / 수정을 허용하지 않는 특징이 있다. 생성은  tuple()로 빈 tuple을 생성할 수 있고 문법적으로 [튜플로 사용하는 변수명] = (원소1, 원소 2...)을 통해 초기화까지 진행할 수 있다.

 

TUPLE에서 제공하는 주요 메서드는 다음과 같은 것들이 있다.

[TUPLE 변수명].count(원소) : TUPLE내부에서 원소를 센다.

[TUPLE 변수명].index(원소) : TUPLE내부에서 원소의 인덱스를 반환한다.

 

....  이게 끝이다. 별도로 라이브러리를 건들지 않는 이상 이 2가지의 함수밖에 튜플은 제공하지 않는다.

다음은 용례이다.

>> my_tuple = (1,2,3,3)

>> my_tuple.count(3)
2

>> my_tuple.index(2)
1

* 여담으로 모든 자료구조에서 index함수는 중복되는경우 대부분 첫 번째 위치를 반환한다 예를 들어 위와 같은 my_tuple에서 my_tuple.index(3)은 2이다. 

 

튜플은 값이 변하지 않기에 Dictionary의 Key로 쓰일 수 있다는 특징이 있다.

 


이제 우리는 Python의 LIST, DICT, SET, TUPLE의 자료구조까지 살펴보았고 자유자재로 다룰 수 있게 되었다.(그렇다 우리는 대단한 거시다) 다음 시간에는 자료구조의 마무리 단계에서 추가적인 Python 테크닉인 슬라이싱(Slicing)에 대하여 알아보고 프로그래밍의 꽃 제어와 반복, 그중에서 반복부터 알아보도록 하자 

우리는 아직 이 직장에서 탈출하지 못했고, 교실 관리 프로그램의 개발자로 일하고 있다. 우리의 교실에는 "김철수", "윤철수" 등 다양한 개성의 학생들이 있지만, 이번에 새로운 전학생을 받게 되었다. 그런데 이런! 새 학생의 이름이 "김철수"이다. 

>> students=["김철수","윤철수","박철수"]
## 이렇게 잘살고 있는 철수교실에

>> students.append("김철수")
## 한명의 김철수가 더 들어오게 된다.

>> print(students)
["김철수","윤철수","박철수","김철수"]

문제가 있다. 우리는 공부를 잘하는 기존의 김철수와 공부를 못하는 김철수의 점수를 프로그램이 헷갈려하는 결과를 주고 싶지 않다. DB를 배운 사람이라면 당연하게 알 수 있는 문제이지만, 유일성을 부여할 수 있는 번호가 필요하다 (가령 학생 번호, 사원번호나 사람의 경우 주민번호가 될 수 있겠다.) 

 

아 좋다! 2차원 배열이 있었다. 그래서 자신있게 [학생 번호, 학생 이름]의 배열을 students에 추가하기로 하였다.

>> students=list()

>> students.append([1,"김철수"])

>> students.append([2,"윤철수"])

>> students.append([3,"박철수"])

>> students.append([4,"김철수"])

>> print(students)
[[1,"김철수"],[2,"윤철수"],[3,"박철수"],[4,"김철수"]]

뭐 좋다.  이렇게 관리해도 되지만 조금 더 안정적인 유일성 부여방법이 Python엔 존재한다.(이런 경우 휴먼에러로 4번이 중복 등록될 수도 있다.) 그 자료구조가 Dictionary 다른 말로는 Dict라고 한다.


Dictionary의 정의와 사용

Dictionary란 Key의 중복을 허용하지 않는 Key, Value 형태의 순서없는 자료구조이다.  생성은 [Dict로 사용할 변수명] = dict()로 생성하거나 문법적으로 {Key1 : Value1, Key2 : Value2 ... }을 사용하여 초기화까지 할 수 있다.

 

Key와 Value 

Dict에서 특정한 Value는 Key를 통해서만 얻을 수 있다.

>> students={1:"김철수",2:"윤철수",3:"박철수",4:"김철수"}

>> print(student[1])
"김철수"

>> print(student[3])
"박철수"

특이한점은 LIST와 다르게 대괄호[] 안에 들어가는 값이 인덱스가 아니라는 점이다.(0에서 시작하는 그 값들이 아니다! Dict는 순서가 없는 자료구조라는 걸 기억하자) 대괄호 안에 들어가는 값은 Key이며 그 Key에 상응하는 Value가 리턴이 된다는 특징이 있다. 

 

또한 변화하지 않는 값이라면 Key로 사용할 수 있다. 이게 무슨 소리냐

>> students={"학생1":"김철수","학생2":"윤철수","학생3":"박철수","학생4":"김철수"}

>> print(student["학생1"])
"김철수"

>> print(student["학생3"])
"박철수"

이것도 된다는 이야기이다. 변화하지 않는 값이기에 값을 추가 / 삭제할 수 있는 LIST는 Dictionary의 Key로 사용할 수 없다. 잘 알아두자 

>> students={["학생1"]:"김철수","학생2":"윤철수","학생3":"박철수","학생4":"김철수"}
## 이건 안된다!

다음은 자주사용되는 DICT의 메서드(함수)이다.

[DICT의 변수명].clear() : DICT의 초기화

[DICT의 변수명].items() : DICT의 (key, value) 쌍을 복사한다.

[DICT의 변수명].keys() : DICT의 Key들을 LIST로 반환한다.(정말로 LIST로 사용하려면 LIST()로 캐스팅 필요)

[DICT의 변수명].value() : DICT의 Value들을 LIST로 반환한다.(정말로 LIST로 사용하려면 LIST()로 캐스팅 필요)

>> students={"학생1":"김철수","학생2":"윤철수","학생3":"박철수","학생4":"김철수"}

>> students.items()
dict_items([('학생1', '김철수'), ('학생2', '윤철수'), ('학생3', '박철수'), ('학생4', '김철수')])

>> students.keys()
dict_keys(['학생1', '학생2', '학생3', '학생4'])

>> students.values()
dict_values(['김철수', '윤철수', '박철수', '김철수'])

>> students.clear()
>> print(students)
{}

* 여담으로 dict으로 정의된 students를 강제로 list(students)해서 강제로 list로 캐스팅하면 key만 list로 바뀐다.

* dict에 새로운 아이템을 추가하는 방법은 새로운키로 변수를 저장하면 된다. (ex : students["학생5"] = "심철수")


SET의 정의와 사용

SET란 Python 2.3부터 지원하는 기능이며, 집합 연산을 수월히 처리하기 위해 생성된 자료구조이다. Dictionary와 비슷하게 중복을 허용하지 않으며, 순서가 없지만 Value 만 존재하는 것이 특징이다.  [SET로 사용할 변수명] = set()로 빈 SET자료구조를 만들 수도 있고, 문법적으로 {1,2,3,4}로 해서 초기화까지 할 수 있다.

>> my_set={4,3,2,1}

>> print(my_set)
{1,2,3,4}

>> a="hello"
>> my_set = set(a)
>> print(my_set)
{'h', 'e', 'l', 'o'}

중간에 문자열 a를 set로 캐스팅한 my_set는 print결과 "l"의 중복을 허용하지 않고 "h", "e", "l", "o"만을 원소로 가짐을 알 수 있다.

 

Set는 집합연산을 위해 만들어진 것 답게 집합 연산과 같은 Union, isdisjoint, difference부터 단순 원소 추가 연산자인 add까지 지원한다. 

 

* 뭐 사실 난 set를 많이 안쓴다. 개인적인 생각으론 중요도도 다른 자료구조에 비해서 중요해 보이지 않고, 다른 자료구조로 처리될 수 있으면 set를 쓸 이유가 없다고 본다. 굳이 비슷한 자료구조가 필요하다면 만들어 쓰는 게 현명하다고 본다.

* set과 list는 상호 set()와 list()를 통해서 캐스팅이 가능하다 단 list > set으로 변환되었을 때 순서는 뒤죽박죽이 된다.


이렇게 이번시간에는 유일성 문제를 해결해주는 자료구조인 DICTIONARY와 SET에 대해서 알아보았다. 다음 시간은 기본자료구조의 마지막인 튜플에 대해서 알아보도록 하자

+ Recent posts