Skip to content

Latest commit

 

History

History
527 lines (371 loc) · 17.6 KB

File metadata and controls

527 lines (371 loc) · 17.6 KB

Python 언어의 기초 1

우선, Python 언어의 기초적인 내용에 대해 알아봅시다.

여러분이 어느 하나의 프로그래밍 언어에 익숙하다면, 새로운 언어를 배우는데 유리합니다. 기본적으로 공유하는 개념들이 있기 때문이지요. 이런 경우, Learn X in Y minutes 사이트를 활용하면 새로운 언어의 특징을 한 눈에 살펴보기 좋습니다.

이 워크샵 이후에 Python을 종합적이고 체계적으로 학습하기 원한다면, Python 공식문서튜토리얼을 권합니다. Python은 문서화가 매우 잘 되어 있기 때문에, 공식문서에 익숙해지는 것이 좋습니다.

(여기서 ‘익숙해진다’고 표현한 것은, 궁금한 것을 구글 등으로 찾았을 때, ‘아, 영어네? 현기증 난다. 다른 문서 없나?’ 하고 창을 닫는 대신, ‘아, 공식문서네? 다른 어떤 문서보다 더 정확하고 풍부한 정보가 담겨있겠군’ 하고 생각하고 문서를 읽어본다는 의미입니다.)

기본적인 Python 언어에 익숙해졌다면, 주요한 라이브러리들을 익힐 차례입니다. Python 표준 라이브러리 문서를 둘러보셔도 좋고, 워크샵 3-4일차에 데이터를 다루는데 주요하게 활용할 라이브러리인 Pandas 패키지의 문서를 둘러보셔도 좋습니다.

출력문

우선 간단한 것들부터 살펴보지요. 우선 출력문과 간단한 사칙연산자입니다.

출력을 하기 위해서는 print() 함수를 사용합니다. print 라고 쓴 후, 그 뒤의 괄호 안에 출력하고 싶은 내용을 적습니다.

Spyder 의 우하단에 있는 IPython console 창에 아래 내용을 입력해보세요.

assets/day-1-spyder-ipy-console.png

# 문자열
print('Hello')
print('안녕하세요?')
Hello
안녕하세요?

곧바로 print 함수의 결과가 다음 줄에 출력되는 것을 볼 수 있습니다.

이번에는 사칙연산을 해볼까요?

1 + 1   # 더하기
3 - 2   # 빼기
2 * 3   # 곱하기
10 / 4  # 나누기
10 % 3  # 나머지
10 // 3 # 몫
2
1
6
2.5
1
3

위에서 살펴본 사칙연산자 이외에도, and, or, not 과 같은 부울 연산자도 있습니다.

True
False
True and False
True or False
not True
not False
True
False
False
True
False
True

아래와 같은 Equality check를 위한 연산자들도 있습니다.

  • ==
  • !=
  • >
  • <
  • >=
  • <=
10 == 10
10 != 10
10 > 5
10 < 5
a = True
a is True
True
False
True
False
True

변수 할당

값을 기억해두고 재사용하려면 변수를 활용합니다. 많은 프로그래밍 언어에서는, = 기호가 ‘같다’라는 의미가 아니라, ‘저장해라’라는 의미로 사용됩니다.

즉, a = 10 이라는 구문은, a는 10과 같다 라는 뜻이 아니라, a에 10이라는 값을 저장해라 라는 뜻입니다.

# a와 b 두 값을 더해봅시다.
a = 10
b = 20
print(a + b)
30
# 10, 20, 30, 40, 50의 평균값을 구해봅시다. 
# 이미 값을 저장한 변수를 아래와 같이 사용할 수 있습니다.
c = 10
c = c + 20
c = c + 30
c = c + 40
c = c + 50
c = c / 5
print(c)
30.0

위의 코드는 설명이 좀 필요하겠네요. 우선,

  • 1행에서 c 라는 변수에 10 이라는 값을 저장했습니다.
  • 2행에서, c 라는 변수의 값에 20 이라는 값을 더하고, 그걸 c 라는 변수에 넣었습니다.
    • 1행에서 c10 을 넣었었죠? 따라서 c + 20 에서 c 에는 10 이 들어있다고 생각하시면 됩니다.
    • 그래서 2행에서의 c = c + 2010 + 20, 즉 30 이라는 값을 c 에 저장하게 됩니다.
  • 3행에서도 c 라는 변수의 값에 30 이라는 값을 더하고, 그걸 c 라는 변수에 넣었습니다.
    • 이번에는 c30 이 담겨있죠? (아까 2행에서 c30 을 넣었습니다.)
    • 그래서 c + 30 에서 c30 을 대입하면, 30 + 30, 즉 60 이라는 값을 c 변수에 다시 넣습니다.

변수로 사용할 이름을 결정하고, 변수명 = 값 의 형태로, 이름을 가진 변수에 값을 저장합니다.

현재 변수에 어떤 값이 저장되어 있는지 확인하려면, Spyder 편집기 우상단에 위치한, Variable explorer 를 확인합니다.

assets/day-1-variable-explorer.png

반복문: for, while, continue, break

여기부터는 실행해야 할 구문이 여러 줄로 늘어납니다. 이제는 IPython console에 직접 코드를 입력하기보다는, 코드를 파일에 저장한 후 한꺼번에 실행하는 방식을 사용합니다.

새 파일 File > New File 을 만들고 아래와 같이 입력한 후 저장 Ctrl-S 하세요. F5 를 눌러 실행해봅시다. 쉽지요?

assets/day-1-savefile.png

반복문은, 일정한 행동들을 반복해서 하게 하는 명령입니다.

기본적으로 가장 많이 사용하는 for 구문의 형태는 아래와 같습니다.

# -*- coding: utf-8 -*-

for i in [0, 1, 2, 3, 4, 5, 6, 7, 9]:
   print(i, end='')
   print(',', end=' ')
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 

위 코드는 아래와 같은 의미입니다.

0부터 9까지 각 숫자에 대하여 (반복한다):
   숫자를 화면에 출력한다
   쉽표를 출력하고 공백 한칸을 출력한다

for 문은 for A in B 형태로 이루어집니다. in 뒤에 오는 B 부분에는 순회할 값들이 들어있는 리스트 등이 올 수 있고, 각 원소를 반복하며 그 값이 A 변수에 저장됩니다.

1: for i in [0, 1, 2, 3, 4, 5, 6, 7, 9]:
2:   print(i, end='')
3:   print(',', end=' ')

편의상 위 코드에 행 번호를 붙여보았습니다. 위 구문은 아래와 같은 순서로 실행됩니다.

  • 1행: i에 첫번째 원소인 0을 할당
  • 2행: i에 대해 print문을 실행. 현재 i에 담긴 값은 0이므로 0이 출력됨
  • 3행: 쉼표 출력
  • 1행: i에 두번째 원소인 1을 할당
  • 2행: i에 대해 print문을 실행. 현재 i에 담긴 값은 1이므로 1이 출력됨
  • 3행: 쉼표 출력
  • 1행: i에 세번째 원소인 2를 할당
  • 2행: i에 대해 print문을 실행. 현재 i에 담긴 값은 2이므로 2가 출력됨
  • 3행: 쉼표 출력
  • 1행: i에 열번째 원소인 9를 할당
  • 2행: i에 대해 print문을 실행. 현재 i에 담긴 값은 9이므로 9가 출력됨
  • 3행: 쉼표 출력

여기서 처음으로 블럭(block)이 등장했습니다. 위 코드에서 print 구문이 있는 행이 블럭입니다. Python에서 블럭은 들여쓰기로 표현되며, 같은 등위의 명령문들을 표현합니다.

아래 코드는 위의 코드와 다르게 동작합니다. for 구문이 실행되는 동안 , 가 매번 출력되지 않고, for 문을 벗어난 뒤 한 번만 출력됩니다. print 문이 for 문 ‘바깥에’ 있기 때문입니다.

# -*- coding: utf-8 -*-

for i in [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]:
   print(i, end='')
print(',', end=' ')  # for문과 같은 들여쓰기 위치에 존재함
0123456789, 

위 코드는 아래와 같은 의미가 됩니다.

0부터 9까지 각 숫자에 대하여 (반복한다):
   숫자를 화면에 출력한다
(반복 실행이 모두 끝난 후에,) 쉽표를 출력하고 공백 한칸을 출력한다

Python에서는 들여쓰기가 매우 중요합니다. 같은 블럭의 코드들은 공백이나 탭의 갯수가 동일해야 합니다. 공백이나 탭의 갯수가 서로 일치하지 않는 경우, ‘IndentationError: unexpected indent’ 오류가 발생하거나 의도하지 않은 동작을 할 수 있습니다.

다시 반복문으로 돌아와서, while 문은 조건이 참일 동안 블럭 안의 내용을 반복해서 수행합니다.

# -*- coding: utf-8 -*-

import random
s = 0

while s < 50:
  s = s + random.randint(0, 10)

print(s)
53

위 코드는 아래와 같은 의미입니다.

누적 값이 50 미만일 동안 (반복한다):
    0~9 사이의 난수를 하나 발생시키고, 그것을 누적 값에 더한다

누적 값을 출력한다

반복문 안에 print 문을 넣으면 결과만을 출력했던 위의 코드와는 다르게, 각 반복 도중에 변화하는 s 값을 관찰할 수 있습니다. print 문이 for 문 ‘안에’ 있기 때문입니다.

# -*- coding: utf-8 -*-

import random
s = 0

while s < 10:
  s = s + 1
  print(s)

print(s)
1
2
3
4
5
6
7
8
9
10
10
누적 값이 10 미만일 동안 (반복한다):
    누적 값에 1을 더한다
    (현재의) 누적 값을 출력한다

누적 값을 출력한다

만약 for 문이나 while 문을 수행하는 도중에 반복 구문을 벗어나려면 break 구문을 사용합니다. continue 구문은 반복 구문을 완전히 벗어나는 대신, 해당 차수의 반복을 건너뜁니다.

위 코드에서 새로 등장한 예약어로 import 라는 것이 있는데, 이것은 ‘확장 기능(모듈)을 불러오는 것’이라고 생각하시면 됩니다. 여기서는 무작위에 대한 기능을 제공해주는 random 이라는 모듈을 불러와 사용할 수 있게 합니다.

random 모듈의 randint 함수는 무작위로 선정할 정수의 [시작, 끝] 범위를 지정하기 위해 두 개의 숫자를 인자로 받습니다.

조건문: if

특정한 조건을 만족할 때만 일련의 행동들을 수행하게 하는 명령입니다.

가장 간단하게는 if A: 형태로 사용합니다.

# -*- coding: utf-8 -*-

import random
s = 0

while True:
  s = s + random.randint(0, 10)
  if s > 50:
    break
  print(s, end=' ')
3 7 17 25 34 40 40 45 

조금 더 복잡한 형태로는 if A: ... else: ... 형태가 있습니다.

# -*- coding: utf-8 -*-

import random

for number in [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]:
    if number == 0:
        continue
    if number % 2 == 0:
        print('{}: even'.format(number))
    else:
        print('{}: odd'.format(number))
1: odd
2: even
3: odd
4: even
5: odd
6: even
7: odd
8: even
9: odd

if 조건을 여러개 사용하고 싶은 경우에는 if A: ... elif B: ... elif C: ... else: ... 형태를 사용할 수 있습니다.

# -*- coding: utf-8 -*-

import random

for number in [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]:
    if number == 0:
        continue
    elif number % 2 == 0 and number % 3 == 0:
        print('{}: multiplier of 6'.format(number))
    elif number % 2 == 0:
        print('{}: multiplier of 2'.format(number))
    elif number % 3 == 0:
        print('{}: multiplier of 3'.format(number))
2: multiplier of 2
3: multiplier of 3
4: multiplier of 2
6: multiplier of 6
8: multiplier of 2
9: multiplier of 3

연습문제

이쯤해서 NetworkX라는 도구를 사용해서 네트워크 그래프를 한번 그려봅시다.

갑자기 약간 복잡하게 느껴질 수 있는데, 시각적인 예제를 다루는 것이 흥미로울 것 같아 마련했습니다.

아래는 네트워크 그래프를 그리는 기초적인 코드입니다. 우선 의사 코드(pseudo code)부터 살펴보겠습니다.

# 빈 네트워크 그래프를 생성한다.
# 네트워크 그래프에 1이라는 ID를 가진 노드를 추가한다.
# 네트워크 그래프에 2라는 ID를 가진 노드를 추가한다.
# 네트워크 그래프를 그린다.

outputs/day1-example-nx-0.png

이 의사 코드를 실제 코드로 옮겨보면 아래와 같이 표현할 수 있습니다.

%matplotlib inline
# networkx 라이브러리를 불러옵니다. 이때 nx라고 별명을 붙여서, 줄여쓸 수 있게 합니다
import networkx as nx

# 텅 빈 네트워크를 생성합니다.
G = nx.Graph()

# 네트워크에 1이라는 ID를 가진 노드를 추가합니다
G.add_node(1)

# 네트워크에 2라는 ID를 가진 노드를 추가합니다
G.add_node(2)

# 네트워크를 공간상에 배치합니다.
positions = nx.spring_layout(G)

# 계산된 위치에 링크와 노드, 라벨을 그립니다.
nx.draw_networkx_edges(G, positions, alpha=0.2);
nx.draw_networkx_nodes(G, positions, node_size=300);
nx.draw_networkx_labels(G, positions);

outputs/day1-example-nx-0.png

G = nx.Graph() 라는 명령을 통해서 빈 네트워크를 생성하고, G.add_node() 라는 명령을 통해서 노드를 추가했습니다. 그리고 뭔가 복잡한 문장들을 입력하니 그래프가 그려진 것을 볼 수 있습니다.

실제로 여러분이 스스로 네트워크 그래프를 그려야 할 상황이라면, Python에서 네트워크 그래프를 그릴 수 있는 방법을 먼저 검색엔진에서 찾아봅니다. 검색엔진에서는 몇 가지의 방법을 제안할테고, 원하는 도구를 결정합니다.

원하는 도구를 결정했다면, 해당하는 도구의 공식 문서를 읽어봅니다. 지금 이 경우에는 NetworkX가 되겠죠. NetworkX의 공식 문서 내용 중에는, 이 도구를 어떻게 사용해야 하는지 설명하는 튜토리얼이 있습니다. 그 문서를 읽어보면, 네트워크를 어떻게 생성하고 노드와 링크를 어떻게 추가하는지, 그림을 어떻게 그리는지 등의 내용이 설명되어 있습니다. 대부분의 경우에는 이런 튜토리얼을 읽으면서 그 도구를 어떻게 사용해야 할지 파악할 수 있습니다.

이번에는 링크를 추가해봅시다.

G.add_edge() 명령을 사용하면 두 노드 사이에 링크를 만들 수 있습니다.

%matplotlib inline
import networkx as nx

G = nx.Graph()
G.add_node(1)
G.add_node(2)

# 1번 노드와 2번 노드 사이에 링크를 연결합니다
G.add_edge(1, 2)

# 네트워크를 공간상에 배치하고 그립니다.
positions = nx.spring_layout(G)
nx.draw_networkx_edges(G, positions, alpha=0.2);
nx.draw_networkx_nodes(G, positions, node_size=50);

outputs/day1-example-nx.png

위의 예제를 아래와 같이 변경해보세요.

  • 현재는 add_node()를 수동으로 2회 호출해서 노드를 2개 그렸는데, for 문을 사용하여 node를 50개 추가하기
  • 현재는 add_edge()를 수동으로 1회 호출해서 링크를 1개 그렸는데, random.randint() 를 사용하여 edge 100개 추가하기

outputs/day1-exercise-1.png

의사 코드(pseudo code)를 한번 작성해봅시다.

빈 네트워크 그래프를 생성한다
50까지 순회할 동안
  노드를 추가한다

100까지 순회할 동안
  50 이하의 랜덤 숫자를 생성한다
  50 이하의 랜덤 숫자를 생성한다
  두 랜덤 숫자를 가지고 링크를 추가한다

참고로, 랜덤 숫자는, random.randint() 함수를 사용하여 아래와 같이 만들 수 있습니다.

import random

print(random.randint(0, 10))
print(random.randint(0, 10))
print(random.randint(0, 10))
print(random.randint(0, 10))
2
1
2
10

의사 코드(pseudo code) 작성하기

여기까지 살펴보면서, 의사 코드(pseudo code)를 적극적으로 사용한 것을 보셨을겁니다.

프로그래밍은, 내가 달성하고자 하는 바를, 프로그래밍 언어의 규칙과 절차에 따라서 표현하는 것이 핵심입니다. 그런데, 프로그래밍 언어에 익숙치 않을 때에는, 의사 코드(pseudo code)를 먼저 작성해보고, 의사 코드 수준에서 절차를 세분화하여, 최종적으로 프로그래밍 언어로 표현하는 연습을 하는 것이 도움이 되는 경우가 있습니다.

의사 코드는 별달리 정해져 있는 규칙은 없고, 자신이 익숙한 자연어, 즉 한국어로 기술하면 됩니다.