5. 파이썬으로 코딩 시작하기(1)

김건희·2022년 12월 14일
0

Fundamental

목록 보기
5/7

5-1. 함수와 변수

(1) 함수 호출하기


수학에서의 함수란 (아주 단순화하면) 입력값(input)에 대해 출력값(output)을 가지는 관계를 가리킵니다. f: x → y 또는 f(x) = y로 표기하는데, 여기서 f는 함수, x는 입력값, y는 출력값을 가리킵니다.

그렇다면 프로그래밍에서의 함수는 어떨까요? 여기서 함수의 의미는 조금 달라집니다. 함수는 불려진 시점에 특정한 작업을 수행하며, 입력값과 출력값은 있을 수도 없을 수도 있답니다.

함수를 하나 불러봅시다. print()라는 함수는 파이썬에 의해 기본적으로 제공되는 함수로, 화면에 문자열을 표시해 주는 역할을 합니다.

[Output]을 확인해 보면 아무것도 보이지 않습니다. 왜일까요? 🤔 아무런 입력값이 없어서 그렇습니다. 그래도 다행입니다. 어떤 함수들은 입력값이 필수라서 입력값이 없을 때 오류를 뱉기 때문입니다.

그렇다면 숫자 1을 입력값으로 넣어 다시 실행해 볼까요?

수학에서 함수를 y=f(x)로 표기하는 것은 우리에게 너무나 익숙한 사실입니다. 이 함수에서 f와 x가 각각 함수의 이름과 입력값을 의미하듯이, print와 괄호 속 1도 동일한 의미를 지닙니다. 프로그래밍 분야에서는 입력값을 주로 인자(argument) 라고 부르는데 함께 기억해두면 좋겠죠?

print() 함수의 괄호 안에서 숫자끼리 덧셈을 하면 어떻게 될까요?

수학의 계산식과 같이 괄호 안의 내용이 먼저 계산되는 것을 볼 수 있습니다. 숫자 대신 글자를 표시하고 싶다면, 프로그램의 코드와 구분해 주기 위해 따옴표 ' 또는 쌍따옴표 "로 내용을 감싸줘야 합니다. 이렇게 감싼 글자들의 한 묶음을 하나의 문자열(string) 이라고 합니다 .

문자열 'Hello'를 출력해 볼까요? 👋

문자열 Hello의 타입은 str로 나오네요.

위에서 print(1 + 1)을 통해 2가 제대로 출력된 것을 확인했었습니다. 문자열끼리 더하면 어떻게 될까요?

문자열끼리 더한 것은 가능하지만, 빼는 것은 불가능하군요. 내용을 훑어보니 발생된 오류의 유형은 TypeError이고, str 타입과 str 타입 간에 - 연산은 지원하지 않음을 알 수 있습니다. 그러므로 문자열끼리는 빼지 말아야겠죠?

이외에도 가지각색의 오류(bug)들을 앞으로 자주 마주하게 되실 테지만 겁먹지는 마세요! 이해하기 어려운 오류는 구글 검색 등을 통해 충분히 해결하실 수 있을 겁니다. 개발을 하는 동안 오류는 떼려야 뗄 수 없는 숙명 같은 존재이므로 앞으로 오류를 잘 이해하도록 노력해야겠죠? 나중에는 오히려 아무 오류가 없을 때 불안해지는 시점이 올 겁니다. 😉👍

(2) 변수 사용하기

f(x) = y에서 f(x)가 '함수'라면, 입력값과 출력값인 x와 y는 '변수'에 해당됩니다.

print()라는 함수에 greeting이라는 변수를 입력값으로 주는 예시를 한번 살펴볼까요?

greeting = '안녕하세요?' 
#- greeting이라는 변수에 '안녕하세요?'라는 문자열을 저장합니다.
print(greeting) 
#- greeting을 출력합니다.
>> 안녕하세요?

사전에서 '변수'를 검색해 보면, 어떤 관계나 범위 안에서 여러 가지 값으로 변할 수 있는 수 라고 정의되어 있습니다. 이처럼 변수는 스스로 값을 갖기보단 다른 값을 가리키는 존재입니다.

위 코드의 첫 번째 줄에서 greeting이라는 변수가 안녕하세요?라는 문자열을 가리키도록 정의했고, 세 번째 줄에서는 print() 함수에 greeting 변수를 입력으로 주어 greeting 변수가 가리키는 값을 화면에 표시하도록 했습니다. 즉, 변수를 정의하기 위해서는 [변수명] = [변숫값]과 같은 형식을 취하면 되며, 이후에는 변수명으로 해당 변숫값을 참조할 수 있습니다.

여기서 또 배울 수 있는 점이 있습니다. 코드가 한 줄 한 줄 순서대로 처리되기 때문에 변수를 정의(define)하기 전에 먼저 사용하려고 하면 오류가 나게 됩니다. 한번 확인해 볼까요?

오류 메시지를 읽어보면 something이라는 변수명이 정의되지 않아서(not defined) 발생된 오류임을 확인할 수 있습니다.

또 다른 경우를 살펴봅시다. 방금 위에서 변수란 어떤 값을 가리키는 존재라고 했죠? 같은 변수명을 재사용하게 될 경우 어떤 값을 가리키는지가 변하게 됩니다.

greeting = '안녕하세요?'
greeting = '안녕!'
print(greeting)
>> 안녕!

이번에는 print(greeting)이 속한 줄의 순서를 조금 바꾼 다음 실행해 볼까요?

greeting = '안녕하세요?'
print(greeting)
greeting = '안녕!'
>> 안녕하세요?

코드는 한 줄씩 순서대로 실행되기 때문에, print() 함수가 불리는 시점의 greeting 변수의 값인 안녕하세요?가 출력됩니다.

(3) 새로운 함수를 정의하기

이미 만들어진 함수를 부르는 것 외에 우리가 직접 함수를 만들 수도 있습니다.

부르면 안녕!이라고 표시하는 함수를 정의해 보겠습니다. 함수는 내부에서 다른 함수를 부르거나 변수를 정의하는 등 다양한 작업을 할 수 있습니다. 따라서 함수를 정의하는 방법이 이전의 변수와는 조금 다릅니다.

참고로, 아래 코드는 실행을 해도 함수를 정의할 뿐 함수 자체를 실행시키지는 않습니다. 즉, [Output]에 아무것도 뜨지 않는 것이 정상이라는 거죠! 🙂

def say_hi():
    print('안녕!')
#- 부르면 '안녕!'이라고 인사해주는 함수를 정의합니다.

def는 함수를 정의(define) 할 때 사용하는 일종의 예약어이며, 함수명은 임의로 만들 수 있습니다. 함수명 뒤에 붙은 괄호는 이 함수에 입력으로 전달되는 값을 받는 자리이며, 입력값이 필요 없는 경우에는 위 코드처럼 함수명 뒤에 ()를 붙여주면 됩니다.

def 함수명() 뒤에 :를 붙여주고, 이어서 이 함수가 불릴 때 실행할 작업들을 한 줄씩 나열해 주면 됩니다. 단, 해당 함수에 포함된 작업이라는 것을 나타내기 위해, def 줄부터 함수가 끝날 때까지 띄어쓰기 4칸으로 들여쓰기를 해주어야 합니다.

🤔 잠깐! 매번 스페이스를 4번이나 눌러줘야 할까?

키보드의 Tab 버튼을 한 번만 누르시면 자동으로 인덴트가 주어집니다.

다만, 코드 스타일에 따라 다를 수 있으며 구글 파이썬 스타일 가이드에 나와있듯이 탭과 스페이스를 혼용해서 사용하면 안 됩니다.

혼용한다면 IndentationError: unindent does not match any outer indentation level 같은 에러가 뜨니 주의해 주세요.

다른 분들과 협업할 때는 특히 주의해야겠죠?

요약하면, 위 say_hi 함수는 다음과 같이 풀이됩니다.

"입력값을 받지 않는 say_hi 함수는 '안녕!'이라는 문자열을 출력해 주는 함수입니다."

say_hi() 함수를 불러서 '안녕!'이 나오는지 한번 확인해 볼까요?

say_hi()
>> 안녕!

여기서 잠깐! 만약 위에서 함수를 정의할 때 들여쓰기를 안 했다면 어떻게 될까요?

실행을 해보면 IndentationError가 뜨는 것을 확인하실 수 있을 겁니다.

이는 들여쓰기 된 코드 블럭, 즉 indented block을 기대했는데 왜 빼먹었냐는 불평입니다. def 줄의 다음 줄부터 함수 정의가 끝날 때까지는 들여쓰기를 유지해야 하며, 이 들여쓰기가 유지되는 구간을 블럭(block)이라고 합니다. 즉, 파이썬에서 들여쓰기는 이 줄의 코드가 위 단계의 코드에 속한다는 것을 표시합니다.

안녕! 다음 줄에 반가워.라고 한 줄 더 표시하고 싶다면, 그다음 줄에 print() 함수를 하나 더 추가해 주면 됩니다. 이번에도 함수를 정의하기만 하는 것이니, 화면에 아무것도 출력되지 않아도 걱정 마세요! 👌

(4) 스코프: 변수의 유효 범위

함수 내에서도 변수를 정의할 수 있습니다.

하지만 이것은 함수 안에서만 일어난 일이라는 것을 명심해야 합니다. 함수가 끝나면 해당 변수는 사라지고, 함수 밖에서 해당 변수를 들여다볼 수도 없습니다. 이게 무슨 말인지 한번 차근차근 알아봅시다. 😎!

아래 코드를 실행하면 에러가 발생합니다.

함수 내에서 선언한 변수를 "함수의 속마음", 밖에서 선언한 변수를 "방송"이라고 생각해 주세요. 방송국이 시민 개개인의 속마음을 알 순 없으니 에러가 납니다.

하지만 반대로 함수 내에서 함수 밖의 변수를 읽는 것은 가능합니다. 개개인이 방송을 듣는 건 가능하죠 👂

name = '하루'
#- name이라는 변수는 문자열 '하루'를 가리킵니다.

def say_name():
    print(name)
#- say_name() 함수의 밖에서 정의된 변수(name), 즉 '하루'를 읽어옵니다.

say_name()

name = '시우'
#- 이제, name이라는 변수는 문자열 '시우'를 가리킵니다.

say_name()
>>> 하루
    시우

더 나아가서 잠시 생각해 봅시다. 함수 안에서 = 을 통해 값을 바꾸면 실제로 바뀔까요? 그렇지 않습니다. 파이썬은 함수 안에서 새로운 변수를 정의하는 것으로만 이해하기 때문이죠.

이게 무슨 말인지 아래 코드를 통해 살펴봅시다.

name = '하루'
#- name은 문자열 '하루'를 가리키는 변수입니다.

def change_name():
    name = '시우'
    #- 여기서 name은 해당 함수 내에서만 문자열 '시우'를 가리킵니다.

change_name()
#- 함수를 호출해도 아무 일도 일어나지 않습니다.

print(name)
#- 첫 줄, 즉 함수 바깥에서 정의된 문자열 '하루'가 출력됩니다.
>>> 하루

개개인이 속마음으로 방송을 어떻게 정의 내리냐는 다르지만, 개인의 해석이 전 국민이 보는 방송 자체를 바꿀 순 없겠죠?

이처럼 특정 위치에서 어떤 변수에 접근할 수 있는지, 또 한 곳에서 정의된 변수가 어디까지 유효한지 정의된 범위를 변수의 스코프(scope) 라고 합니다.

즉, 위의 코드에서 name = '하루'는 함수 내부를 포함해 코드 어디에서든 참조할 수 있으므로, 전역 스코프(global scope) 를 갖는 변수라고 할 수 있습니다. 반대로 name = '시우'는 change_name() 내부에서 정의되어 밖에서 볼 수 없으므로, 지역 스코프(local scope) 를 갖는 변수입니다.

(5) 함수에 인자 전달하기

만약 원하는 이름을 주고 [이름], 안녕!을 표시하게 하려면 어떻게 해야 할까요? 아래 코드와 같이 명시적으로 함수에 입력값을 전달해 주는 게 바람직합니다.

say_hi_somebody()라는 새로운 함수를 한번 정의해 보겠습니다. 🙋

'준이, 안녕!' 이라는 결과를 확인하셨나요? 그렇다면, say_hi_somebody(name) 함수를 찬찬히 살펴보겠습니다.

함수를 정의하는 라인을 주목해 보면, 괄호 () 안에 name이라는 입력값이 정의된 것을 확인할 수 있습니다. 이 입력값의 자리에 들어오는 값은 해당 함수 내에서 name이라는 변수로 불러서 사용할 수 있습니다. 이처럼 입력값으로 주어진 인자(argument)를 받는 변수를 매개변수(parameter) 라고 합니다. 즉, 위 예제에서 함수 내부의 name은 매개변수이고, 외부에서 함수를 부를 때 넣어준 '준이'는 그 매개변수에 들어가는 인자입니다.

만약 위의 함수에 이름을 안 넣고 함수를 부르면 어떻게 될까요?

오류가 납니다. 함수는 가끔 아기 👶 같습니다. 저희가 매개변수라는 신제품 분유를 사주기로 약속했는데, 아직 사주지 않아 떼를 쓰는 것입니다.

say_hi_somebody()라는 함수도 name이라는 매개변수에 들어갈 인자 없이 살 수 없는 몸입니다.

오류 메시지는 say_hi_somebody()라는 함수가 name이라는 매개변수에 들어갈 필수 위치 기반 인자 하나를 누락했다고 말하고 있습니다. 결국 단순하게 이해하자면, say_hi_somebody() 함수를 정의할 때 name이라는 매개변수를 정의했으니, 여기에 들어갈 인자를 빼고 부르면 안 된다는 말입니다.

그럼 이번에는 반대로, 아까 입력값 없이 정의했던 say_hi_nice() 함수에 억지로 입력값을 넣어봅시다.

이번에도 오류가 나지만 내용은 살짝 다릅니다. say_hi_nice() 함수는 위치 기반 인자를 받지 않는데 한 개(준이)가 주어졌다는 말입니다. 우리 아기 함수가 지금은 뭘 먹고 싶지 않은데 억지로 먹이면 안 되겠죠. 함수를 호출할 때는 미리 정의된 입력값을 넣어야 한다는 교훈을 얻을 수 있습니다.

그럼 print() 함수처럼 입력값이 있든 없든 불평 없이 자기 할 일을 하는 함수를 정의할 수는 없을까요? 🤔

이번에는 이름을 뺐을 때 어떻게 동작하는지 확인해 봅시다.

>>> 안녕, somebody!

입력값이 주어지면 그 입력값을 그대로 표시하고, 없으면 somebody라는 값이 있는 것처럼 동작합니다. 즉, 함수가 받을 매개변수의 기본값을 지정해 주면, 입력값이 없을 경우 해당 기본값을 사용하게 됩니다.

(6) 함수에 인자 여러 개 한꺼번에 전달하기

지금까지는 한 명에게만 인사했지만, 이제 난이도를 두 배로 높여서 두 명에게 인사해 봅시다. ✌

여기서 이름을 하나 빼먹는다면?

오류를 확인해 봅시다. 이유식 🍼 두 개가 아니라며, 약속했던 name2를 내놓으라고 합니다. 👶

참고로, 함수를 정의할 때 쓰인 인자의 이름을 알고 있다면, 함수를 호출할 때 직접 붙여줄 수도 있습니다. 아래의 코드는 그 의미상 say_hi_couple('그리', '단테')와 동일합니다.

아기 함수에게 이유식을 줘야 하는 우리 부모 입장에서 더욱 편하겠죠? 각 분유에 레이블을 붙여놓는다면 뭐가 뭔지 알기 쉽기 때문입니다.

하지만 함수를 정의할 때 약속한 이름이 아닌 엉뚱한 이름을 주면?

😭 이런! 아기 함수가 체해서 화를 내네요. 잘못된 이유식을 줘버렸기 때문입니다. 다음부턴 꼭 조심해야겠어요.

한편, 입력값이 여러 개일 때도 각 입력값마다 기본값을 지정해 줄 수 있습니다.

단, 이 경우 기본값이 있는 인자들이 기본값이 없는 필수 인자들의 뒤에 와야 합니다.

오류를 살펴보면 기본값(default)이 없는 인자가 기본값이 있는 인자 뒤에 오면 SyntaxError에 해당한다고 합니다.

위처럼 정의해놓고 say_hi_couple_default_wrong('단테')와 같이 인자를 하나만 주고 함수를 호출하면, 과연 생략된 하나의 인자를 name1으로 봐야 할지, name2로 봐야 할지 불분명하기 때문입니다.

(7) 함수의 결과로 값을 반환하기

위에서 함수는 입력값(input)과 출력값(output)을 가질 수 있다고 했습니다. 위에서 우리는 입력값을 가진 함수를 정의하고 사용하는 방법을 살펴보았지만, 사실 여태까지 값을 출력하는 함수는 아직 살펴보지 않았습니다. 화면에 표시(print)하기는 했지만요.

이게 도대체 무슨 충격적인 소리인지 알아보기 위해서, 일단 여태까지의 방법으로 숫자 두 개를 더하는 함수를 정의해 봅시다.

일단 위의 코드가 어떤 순서로 실행될지 생각해 봅시다. 마치 수학식처럼, 가장 안쪽의 괄호를 가진 add(1, 2)가 먼저 실행되고, 그 이후 옆의 + 3을 더한 뒤, 가장 바깥쪽의 괄호인 print()가 실행됩니다. add()로 인해 입력값인 1과 2의 합인 3이 나오고, 거기에 3을 다시 더해서 print()를 했으니 6이 표시되어야 할 것 같습니다.

하지만 실제 결과는?

세상은 그렇게 호락호락하지 않습니다. 마음을 추스르고 오류 메시지를 읽어봅시다. 뭔지는 아직 잘 모르겠지만 NoneType과 int(정수, integer) 사이에 + 연산은 금지라고 합니다. 순서상 우리가 + 뒤에 쓴 3이 정수(int)니까, 눈치를 보면 앞의 NoneType은 add(1, 2)를 가리키는 거겠죠? Type은 뭔지 아직 잘 모르겠지만 그 앞의 None을 보면 무언가가 없다는 것 같습니다. 그렇습니다. add()에서 우리는 화면에 표시하라는 print() 함수를 부르긴 했지만, 이 함수의 결과가 무엇인지 명시하지 않아서 그렇습니다.

이처럼 함수가 실행된 뒤 그 결과를 가지고 무언가를 하고 싶다면, return으로 이 값을 출력값(output)으로서 반환(return)하라고 명시적으로 표시해 줘야 합니다.

print() 안의 add_and_return(1, 2)가 먼저 실행되면서, add_and_return() 함수 안 첫 번째 줄인 print(number1 + number2)가 실행되어 화면에 3이 표시되고, 이후에 return number1 + number2로 3이 add_and_return() 함수의 출력값으로서 반환됩니다. 그럼 이제 print(add_and_return(1, 2) + 3)print(3 + 3)과 같게 되고, 최종적으로 print(6)이 되어 화면에 6이 출력됩니다.

여기서 문제입니다. 다음의 끔찍한 코드는 어떤 순서로 결과를 표시할까요? 실행하기 전에 한번 생각해 보고 맞춰보세요.

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

여러분이 생각했던 답과 결과가 같았나요?

위의 코드는 먼저 print_and_return('B', 'C', 'D')이 호출됩니다. print_and_return('B', 'C', 'D')이 호출되면서 이 함수 안에 있는 함수 print_two(word3, word2)이 호출되어 D와 C가 출력됩니다. 그 후 print_two('A', print_and_return('B', 'C', 'D'))이 호출되면서 print('A')과 print(print_and_return('B', 'C', 'D'))이 실행되죠. print('A')에서는 A가, print(print_and_return('B', 'C', 'D'))에서는 return 값인 B가 출력됩니다. 따라서 출력 결과가 D C A B로 나옵니다.

설명이 복잡하지만 천천히 코드를 뜯어보면서 생각하면 이해가실 거예요.

5-3. 제어문

지금까지 함수와 변수에 대한 기본적인 내용을 돌아보았습니다.

우리가 파이썬에서 기본으로 제공되는 print() 함수를 즐겨 사용했던 것처럼, 앞으로도 모든 함수를 우리가 직접 만들지는 않을 겁니다.

다른 사람들이 이미 만들어놓은 함수를 부르기만 하면 이미 만들어진 함수가 화면에 글자를 표시해 주고, 수치 데이터를 그래프로 그려주고, 사진을 파일로 만들어 저장해 줍니다. 소프트웨어 개발은 이렇게 이미 있는 기본 블록들을 조립해 건물을 쌓아가는 방식으로 이뤄집니다. 따라서 우리는 함수 등을 통해 제공된 기능들을 "적절한 흐름"에 따라서 조합하기만 하면 됩니다.

지금부터는 특정 조건에 따라 알아서 필요한 횟수만큼 반복해서 실행하는 등 프로그램의 "흐름을 제어(control)"하는 방법에 대해 배워보겠습니다.

(1) if: 진실 혹은 거짓

어떤 명제가 참인지 거짓인지에 따라 코드의 실행 여부를 결정할 수 있습니다. ⚖

입력값으로 주어진 숫자가 0 이상일 경우에만 화면에 숫자를 표시하는 함수를 한번 정의해 봅시다.

def print_if_positive(number):
    if number >= 0:
        print(number)
#- 숫자가 0보다 크거나 같을(>=) 경우 즉, 0 이상일 경우에만 숫자를 출력합니다.

print_if_positive(1)
print_if_positive(-1)
>> 1

def로 함수를 정의(define)하던 것과 비슷하지만, 이번에는 만약(if)이라는 키워드를 사용합니다.

if 명제:의 형식으로 표시하며, 이후에 들여쓰기 된 코드 블록의 내용은 if 키워드 다음의 명제가 참일 때에만 실행됩니다. 명제를 구성할 때 사용할 수 있는 비교 연산자(conditional operator) 에는 초과 또는 미만(>, <), 이상 또는 이하(>=, <=), 값이 같음 또는 다름(==, !=) 등이 있습니다.

위의 함수를 변형해서 양이면 +, 음이면 -를 표시하려면 어떻게 할까요?

if number >= 0:에 속하는 블록 뒤에 if와 동일한 들여쓰기 깊이로 다시 if number < 0:를 추가하는 방법도 있겠지만, 그 이외의 경우(else)를 나타내는 else:를 사용해서 앞의 명제가 거짓인 경우에 실행할 코드를 손쉽게 명시할 수 있습니다.

def print_whether_positive_or_negative(number):
    if number >= 0:
        print('+')
    else:
        print('-')
#- 숫자가 0보다 크거나 같으면 +를, 작으면 -를 출력합니다.

print_whether_positive_or_negative(1)
print_whether_positive_or_negative(-1)
>> +
   -

그런데 0이 양수(positive)였던가요? 🤔

0에 대한 조건문을 추가하려면 어떻게 할까요?

def print_whether_positive_or_negative_or_zero(number):
    if number > 0:
        print('+')
    elif number == 0:
        print('0')
    else:
        print('-')
#- 숫자가 양수이면 +를, 음수이면 -를, 양수도 음수도 아닌 0일 경우 그대로 0을 출력합니다.

print_whether_positive_or_negative_or_zero(1)
print_whether_positive_or_negative_or_zero(0)
print_whether_positive_or_negative_or_zero(-1)
>> +
   0
   -

위와 같이 else if를 줄인 elif로 if 뒤, else 전에 새로운 조건문을 추가할 수 있습니다.

난이도를 한 단계 높여봅시다. 이번엔 양수이면서 짝수일 때만 숫자를 화면에 표시해 보려 합니다.

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)
>> 2

위의 코드 중 % 연산자는 앞의 숫자를 뒤의 숫자로 나눈 나머지를 의미합니다.

보시면 두 개의 명제(양수인가 짝수인가)를 and(그리고)라는 논리 연산자(logical operator) 로 묶었습니다. 그 결과로 양쪽 명제가 모두 참일 때만 if 조건문에 속한 코드 블록이 실행됩니다.

반대로 음수이거나, 혹은 음양에 상관없이 홀수인 경우에만 표시하려면 어떻게 할까요?

def print_if_negative_or_odd(number):
    if (number < 0) or (number % 2 != 0):
        print(number)
#- 숫자가 음수이거나(or) 홀수일 때 해당 숫자를 출력합니다.
#- 음수 : number < 0
#- 홀수 : number % 2 != 0 즉, 짝수가 아닐 때

print_if_negative_or_odd(1)
print_if_negative_or_odd(-1)
print_if_negative_or_odd(2)
print_if_negative_or_odd(-2)
>> 1
   -1
   -2

or(또는)이라는 논리 연산자는 양쪽의 명제 중 한 쪽이라도 참일 경우에 작동합니다.

(2) while: 조건이 참인 동안 반복

def print_if_negative_or_odd(number):
    if (number <= 0) or (number % 2 != 0):
        print(number)

print_if_negative_or_odd(1)
print_if_negative_or_odd(-1)
print_if_negative_or_odd(2)
print_if_negative_or_odd(-2)
#- print_if_negative_or_odd 함수를 총 4번 호출합니다.
#- 매개변수(number)의 인자를 각각 다르게(1, -1, 2, -2) 부여한 것을 확인할 수 있습니다.
>> 1
   -1
   -2

위 코드에서 우리는 1, -1, 2, -2를 차례대로 하나하나 입력했었습니다. 그런데 while 반복문을 사용하면 컴퓨터가 자동으로 하나씩 계산하도록 할 수 있습니다. 참고로, 아래 코드의 fibonacci() 함수는 n번째 피보나치 수를 반환하는 함수입니다.

잠깐! fibonacci() 함수는 어떻게 작동하는 거지?

스스로를 호출하는 함수를 "재귀 함수"라고 합니다.

return 쪽을 보시면 fibonacci(n-2) + fibonacci(n-1)를 반환하네요. 아래 사진을 참고하시면 더 이해가 될 것입니다.

이번 노드의 재귀 함수와 치킨 (심화) 스텝에서 다시 등장하는 친구니 지금 이해를 해보셔도 좋습니다. 아직 어렵다면 while 문에만 일단은 집중을 해볼게요!


while 문은 코드 블록을 실행하기 전 가장 먼저 조건문을 검사해서, 조건문이 참이면 코드 블록을 실행합니다.

즉, 처음 실행 시 마지막 줄(4행)에서 n은 2가 되고, n <= 20이 참이니 다시 3행으로 돌아가 print(fibonacci(2))를 실행합니다. 그리고 다시 그다음 줄에서 n은 3이 되고, 다시 3행으로 돌아가고.. n이 21이 되면 그제서야 while에 속하는 들여쓰기 코드 블록을 빠져나와 print('끝!')을 실행합니다.

이러한 반복문들을 루프(loop, 고리)라고 부릅니다. 그리고 반복문이 끝없이 계속 실행되는 경우를 무한 루프(infinite loop)라고 부릅니다. 예를 들어, 아래의 명령을 실행한다면 강제로 종료하기까지 영원히 계속 실행됩니다. 👻

(3) for : 하나씩 반복

파이썬에는 while 말고도 for이라는 반복문이 있습니다.

while 뒤에는 참과 거짓이 갈릴 수 있는 명제가 온다면, for 뒤에는 a in A의 형태로, 값이 여러 개 들어있는 목록 A에서 값을 하나씩 꺼내서 a 변수에 담아 반복문을 실행합니다.

설명이 어려우니 한번 예를 들어 이해해 보겠습니다.

'Hi'라는 문자열을 뜯어보면 사실 'H'라는 문자와 'i'라는 문자가 순서대로 이어지는 형태를 가지고 있습니다. 즉, 'Hi' 안에는 'H'와 'i'라는 값이 하나씩 순서대로 들어있습니다.

print('H' + 'i' == 'Hi')
>> True

이렇게 줄줄이 굴비처럼 엮여서 하나씩 순서대로 넘길(iterate) 수 있는 값들을 반복 가능한(iterable, 이터러블) 객체 라고 합니다. for 루프를 써서 순서대로 엮인 값들을 하나씩 처리할 수 있습니다.

그럼, 'Hello'의 글자를 하나씩 print() 해 봅시다.

for character in 'Hello':
    print(character)
>> H
   e
   l
   l
   o

이해를 위해 한번 순서대로 따라가봅시다.

위의 for 문이 실행되면, 일단 'Hello'의 첫 글자인 'H'가 character라는 변수에 할당됩니다.

이후에는 'e'부터 똑같이 한 글자씩 print()가 실행되며, 마지막 'o'를 마친 뒤에 해당 for문의 코드 블록에서 빠져나오게 됩니다.

문자열 외에도 어떤 값들에 for문을 쓸 수 있는지는 다음 스텝에서 알아봅시다. 🙂👍

profile
게임광 AI 그루~~

0개의 댓글