day 5 파이썬으로 코딩 배우기
파이썬으로 코딩 시작하기
파이썬의 기본적인 개념들을 익히는 단원입니다.
변수(variable)
-
함수(function)
-
연산자(operator)
-
제어문(control statements)
-
자료형(data types)
함수 (function)
print()
수학에서의 함수란 (아주 단순화하면) 입력값(input)에 대해 출력값(output)을 가지는 관계를 가리킵니다. f: x → y 또는 f(x) = y로 표기하는데, 여기서 f는 함수, x는 입력값, y는 출력값을 가리킵니다.
greeting = '안녕하세요?'
print(greeting)
greeting = '안녕!'
안녕하세요?
코드는 한 줄씩 순서대로 실행되기 때문에, print() 함수가 불리는 시점의 greeting 변수의 값인 안녕하세요?가 출력됩니다.
def say_hi_nice():
print('안녕!')
print('반가워.')
#- 새로운 함수를 정의합니다.
say_hi_nice()
#- 함수를 호출합니다.
..
..
안녕!
반가워.
함수 내장 변수정의
함수 내에서도 변수를 정의할 수 있습니다. 하지만 이것은 함수 안에서만 일어난 일이라는 것을 명심해야 합니다. 함수가 끝나면 해당 변수는 사라지고, 함수 밖에서 해당 변수를 들여다볼 수도 없습니다.
name = '하루'
#- name은 문자열 '하루'를 가리키는 변수입니다.
def change_name():
name = '시우'
#- 여기서 name은 해당 함수 내에서만 문자열 '시우'를 가리킵니다.
change_name()
#- 함수를 호출해도 아무 일도 일어나지 않습니다.
print(name)
#- 첫 줄, 즉 함수 바깥에서 정의된 문자열 '하루'가 출력됩니다.
이처럼 특정 위치에서 어떤 변수에 접근할 수 있는지, 또 한 곳에서 정의된 변수가 어디까지 유효한지 정의된 범위를 변수의 스코프(scope) 라고 합니다.
즉, 위의 코드에서 name = ‘하루’는 함수 내부를 포함해
함수와 변수 (6) 함수에 인자 여러 개 한꺼번에 전달할 수 있습니다. 한편, 입력값이 여러 개일 때도 각 입력값마다 기본값을 지정해줄 수 있습니다.
단, 이 경우 기본값이 있는 인자들이 기본값이 없는 필수 인자들의 뒤에 와야 합니다.
def say_hi_couple_default(name1, name2='nobody'):
print(name1 + ', ' + name2 + ' 안녕!')
코드 값 반환하기
def print_two(word1, word2):
print(word1)
print(word2)
def print_and_return(word1, word2, word3):
print_two(word3, word2)
return word1
print_two('A', print_and_return('B', 'C', 'D'))
..
..
D
C
A
B
제어문 (control)
특정 조건에 따라 알아서 필요한 횟수만큼 반복해서 실행하는 등 프로그램의 “흐름을 제어(control)”하는 방법에 대해 배워보겠습니다.
if문
def print_if_positive_and_even(number):
if (number > 0) and (number % 2 == 0):
print(number)
#- 숫자가 양수이고(and) 짝수일 때 해당 숫자를 출력합니다.
#-- 양수 : number > 0
#-- 짝수 : number % 2 == 0 즉, 숫자를 2로 나눈 나머지가 0인 경우
print_if_positive_and_even(1)
print_if_positive_and_even(-1)
print_if_positive_and_even(2)
print_if_positive_and_even(-2)
위의 코드 중 % 연산자는 앞의 숫자를 뒤의 숫자로 나눈 나머지를 의미합니다.
보시면 두 개의 명제(양수인가 짝수인가)를 and(그리고)라는 논리 연산자(logital operator) 로 묶었습니다. 그 결과로 양쪽 명제가 모두 참일 때만 if 조건문에 속한 코드 블럭이 실행됩니다.
while문
아래 코드의 fibonacci() 함수는 n번째 피보나치 수를 반환하는 함수입니다.
def fibonacci(n):
if n <= 2:
return 1
else:
return fibonacci(n-2) + fibonacci(n-1)
n = 1
while n <= 20:
print(fibonacci(n))
n = n + 1
print('끝!')
스스로를 호출하는 함수를 “재귀 함수”라고 합니다.
return 쪽을 보시면 fibonacci(n-2) + fibonacci(n-1)를 반환하네요. 아래 사진을 참고하시면 더 이해가 될 것입니다.
for문
for character in 'Hello':
print(character)
..
..
H
e
l
l
o
자료형(data type)
print(type(1))
..
..
<class 'int'>
정수는 무한하지만 우리 컴퓨터의 메모리는 유한하다는 점입니다. 64비트 컴퓨터의 경우 기본적으로 64비트의 공간에 하나의 숫자를 저장할 수 있습니다. 이렇게 되면 2^64(=18,446,744,073,709,551,616)개의 숫자만 인식할 수 있습니다. 즉, 음과 양을 모두 생각하면 -9,223,372,036,854,775,808부터 9,223,372,036,854,775,807까지의 숫자만을 표현할 수 있다는 뜻입니다.
물론 해결법은 있습니다. 💡
우리가 어릴 때 숫자를 세다가 손가락이 부족하면 발가락까지 쓰던 것처럼, 큰 숫자를 표현할 때는 64비트 이상의 공간을 사용하면 됩니다. 다만 이렇게 숫자를 담을 메모리 크기를 수동으로 설정해주어야 하는 프로그래밍 언어들이 있는 반면, 우리의 파이썬은 다행히 숫자가 커지면 알아서 메모리를 더 사용하기에 안심해도 됩니다.
number = 1000 ** 10
print(number)
..
..
1000000000000000000000000000000
float
print(type(1.1))
..
..
<class 'float'>
print(1 == 1.0)
print(1 + 1.0)
..
..
True
2.0
print(float(1))
print(type(float(1)))
print(int(1.0))
print(type(int(1.0)))
..
..
1.0
<class 'float'>
1
<class 'int'>
부동소수점 수(floating point number, 줄여서 float)라는 것은 뭘까요? 이것을 이해하려면 고정소수점 수(fixed point number)라는 것과 함께 이해하면 좋습니다. 고정소수점이든 부동소수점이든 모두 소수를 표현하는 방식일 뿐입니다.
1.0을 32bit의 고정소수점 수와 부동소수점 수로 각각 표현해 보면
고정소수점의 경우 1bit(부호) + 16bit(정수) + 15bit(소수)
고정소수점 : 0 0000000000000001 000000000000000
부동소수점의 경우 1bit(부호) + 8bit(지수) + 23bit(가수)
부동소수점 : 0 01111111 00000000000000000000000
NoneType
print(type(None))
..
..
<class 'NoneType'>
아무것도 없음을 뜻하는 None이 바로 그 값입니다. 0도 아무것도 없다는 뜻 아니야?라고 생각하시는 분들은 아래 도표를 참조해주시기 바랍니다.
불리언(boolean)
print(type(True))
print(type(False))
..
..
<class 'bool'>
<class 'bool'>
print(not True)
print(not not True)
..
..
False
True
print(bool(None))
print(bool(0))
print(bool(1.1))
..
..
False
False
True
문자열(string)
print('He said, "spam."')
He said, "spam."
문자열 안에서 따옴표 앞에 \를 붙여서 이건 코드 상의 기호가 아닌, 문자 그대로로 해석하라고 표시(escape)할 수 있습니다.
print('Quote(\') and double quote(\")')
Quote(') and double quote(")
괄호 안의 문자열 여러 개는 파이썬이 알아서 합칩니다.
print('Hello ' 'June')
Hello June
for character in 'Hello':
print(character)
..
..
H
e
l
l
o
컨테이너 자료형들은 뒤에 [숫자]를 붙여서 해당 순서 인덱스(index) 에 해당하는 값만 쏙 뽑아올 수 있습니다.
message = 'Hello'
print(message[1])
e
message = 'Hello'
print(message[-1])
o
message = 'Hello'
print(message[0:4])
Hell
message = 'Hello'
print(message[2:])
llo
message = 'Hello'
print(message[::1]) # 기본 (한 칸 씩)
print(message[:-1:1]) # 기본 (한 칸 씩)
print(message[::2]) # 두 칸 씩
Hello
Hell
Hlo
message = 'Hello'
print(message[::-1]) # 거꾸로 출력
olleH
튜플과 리스트(tuple and list)
튜플의 경우에는 괄호() 안에 원하는 값들을 쉼표(,)로 구분해서 써주면 됩니다.
numbers = (1, 2, 3)
for number in numbers:
print(number)
mixed_tuple = ('Hello', 0, True)
print(tuple_123[0])
Hello
하지만 값을 변경할 수는 없습니다. 아래 코드는 에러가 납니다.
tuple_123 = (1, 2, 3)
tuple_123[0] = 0
TypeError Traceback (most recent call last)
튜플 안에 튜플을 넣을 수도 있습니다.
nested_tuple = ((1, 2), (3, 4))
print(nested_tuple[1][0])
3
튜플끼리 덧셈 연산자를 통해 합칠 수도 있습니다.
tuple_a = (1, 2)
tuple_b = (3, 4)
print(tuple_a + tuple_b)
(1, 2, 3, 4)
in 연산자를 써서 특정한 값이 튜플 안에 있는지 없는지도 검사할 수 있습니다.
tuple_abc = ('a', 'b', 'c')
print('a' in tuple_abc)
print('d' in tuple_abc)
True
False
리스트는 튜플과 거의 같습니다. 괄호만 대괄호([, ])로 바꿔주면 됩니다.
list_a = [1, 2]
list_b = ['3', '4']
print(list_a, list_b)
[1, 2] ['3', '4']
그리고 튜플과 달리 값을 바꿀 수도 있습니다.
1
list_123 = [1, 2, 3]
2
list_123[0] = 0
3
print(list_123)
[0, 2, 3]
변수를 한번 정의해놓고 변수명 뒤에 .append()라는 특별한 함수를 뒤에 붙여서 값을 하나씩 추가하거나, .remove()를 통해 특정 값을 빼거나, .pop()을 통해 특정 순서의 값을 뺄 수 있다는 점입니다.
list_123 = [1, 2, 3]
list_123.append(4)
print(list_123)
list_123.remove(4)
print(list_123)
list_123.pop(0)
print(list_123)
[1, 2, 3, 4]
[1, 2, 3]
[2, 3]
dictionary
딕셔너리(dictionary)도 값을 여러 개 포함하는 컨테이너 자료형의 일종입니다.
리스트와 차이점은 숫자로 된 인덱스를 쓰는 대신, 직접 인덱스를 원하는 대로 지정할 수 있다는 점입니다.
conductor = {'first_name': '단테', 'last_name': '안'}
conductor['gender'] = 'male'
print(conductor)
{'first_name': '단테', 'last_name': '안', 'gender': 'male'}
제거하고 싶다면 리스트와 마찬가지로 .pop()을 사용하면 됩니다.
conductor = {'first_name': '단테', 'last_name': '안'}
conductor.pop('last_name')
print(conductor)
{'first_name': '단테'}
딕셔너리에 for 루프문을 사용하면 기본적으로 키 값만 돌려줍니다. 하지만 .items()를 사용해서 키와 값을 둘 다 뽑아올 수도 있습니다.
conductor = {'first_name': '단테', 'last_name': '안'}
for key, value in conductor.items():
print(key + ' : ' + value)
first_name : 단테
last_name : 안
summary
-
함수(function): 불려진 시점에 특정한 작업을 수행하며, 입력값과 출력값(반환값)을 가질 수 있습니다.
인자(argument): 함수를 호출할 때 전달하는 입력값입니다.
매개변수(parameter): 함수가 실행될 때 입력값이 들어올 변수입니다.
반환값(return value): 함수가 종료될 때 호출지점으로 전달할 출력값입니다.
-
변수(variable): 값을 가리키는 이름입니다.
스코프(scope): 변수가 유효한 범위입니다.
-
연산자(operator): 주어진 값들에 대해 정해진 연산을 수행합니다.
수리 연산자(mathematical operator): +, -, *, /, \, **
비교 연산자(comparison operator): ==, !=, <, >, <=, >=, is
논리 연산자(logical operator): and, or
소속 연산자(membership operator): in
-
제어문(control statements): 코드 블럭의 흐름(실행 여부, 반복)을 제어합니다.
if: 명제가 참이면 실행합니다.
else: if 명제 이외의 경우에 실행합니다.
elif: if 명제 이외의 경우에 또 다른 명제가 참일 경우에 실행합니다.
while: 명제가 참일 동안 반복합니다.
for: 주어진 값들 하나씩 반복합니다.
-
자료형(data types): 값들의 종류를 나타냅니다.
정수(int), 부동소수점 수(float), 불리언(bool), 문자열(str), 튜플(tuple), 리스트(list), 딕셔너리(dict)
심화학습(fibonacci memoization)
최초의 n이 커질수록 속도는 기하급수적으로 느려지는 점입니다.
fibonacci(n-1) + fibonacci(n-2)를 통해 구한 값은 memory에 저장을 하여 계산량을 줄여봅시다.
memory = {1: 1, 2: 1}
def fibonacci(n):
if n in memory:
number = memory[n]
else:
number = fibonacci(n-1) + fibonacci(n-2)
memory[n] = number
return number
print(fibonacci(100))
print(memory)
354224848179261915075
{1: 1, 2: 1, 3: 2, 4: 3, 5: 5, 6: 8, 7: 13, 8: 21, 9: 34, 10: 55, 11: 89, 12: 144, 13: 233, 14: 377, 15: 610, 16: 987, 17: 1597, 18: 2584, 19: 4181, 20: 6765, 21: 10946, 22: 17711, 23: 28657, 24: 46368, 25: 75025, 26: 121393, 27: 196418, 28: 317811, 29: 514229, 30: 832040, 31: 1346269, 32: 2178309, 33: 3524578, 34: 5702887, 35: 9227465, 36: 14930352, 37: 24157817, 38: 39088169, 39: 63245986, 40: 102334155, 41: 165580141, 42: 267914296, 43: 433494437, 44: 701408733, 45: 1134903170, 46: 1836311903, 47: 2971215073, 48: 4807526976, 49: 7778742049, 50: 12586269025, 51: 20365011074, 52: 32951280099, 53: 53316291173, 54: 86267571272, 55: 139583862445, 56: 225851433717, 57: 365435296162, 58: 591286729879, 59: 956722026041, 60: 1548008755920, 61: 2504730781961, 62: 4052739537881, 63: 6557470319842, 64: 10610209857723, 65: 17167680177565, 66: 27777890035288, 67: 44945570212853, 68: 72723460248141, 69: 117669030460994, 70: 190392490709135, 71: 308061521170129, 72: 498454011879264, 73: 806515533049393, 74: 1304969544928657, 75: 2111485077978050, 76: 3416454622906707, 77: 5527939700884757, 78: 8944394323791464, 79: 14472334024676221, 80: 23416728348467685, 81: 37889062373143906, 82: 61305790721611591, 83: 99194853094755497, 84: 160500643816367088, 85: 259695496911122585, 86: 420196140727489673, 87: 679891637638612258, 88: 1100087778366101931, 89: 1779979416004714189, 90: 2880067194370816120, 91: 4660046610375530309, 92: 7540113804746346429, 93: 12200160415121876738, 94: 19740274219868223167, 95: 31940434634990099905, 96: 51680708854858323072, 97: 83621143489848422977, 98: 135301852344706746049, 99: 218922995834555169026, 100: 354224848179261915075}
프로그래밍에서 이렇게 중간 계산값을 기억해놓고, 다시 계산하는 대신 값을 바로 읽어 쓰는 방식으로 계산 시간을 줄이는 기법을 메모이제이션(memoization) 이라고 합니다.
Leave a comment