F37.101 컴퓨팅 기초: 처음 만나는 컴퓨팅(First Adventures in Computing)

Chapter 7. 함수의 기본#

학습목표와 기대효과

  • 학습목표

    • 함수를 정의하는 방법과 호출하는 방법을 알아보자.

    • 함수 전달인자, 매개변수, 반환에 대해 알아보자.

    • 지역변수와 전역변수에 대해 알아보자.

  • 기대효과

    • 자주 사용하는 기능을 함수로 만들어놓고 사용할 수 있다.

함수는 프로그램에서 자주 사용되는 코드를 만들어 두고 필요할 때마다 호출해서 사용하는 기능(function)이다. 자주 사용하지 않는 코드라도 코드를 구조화 체계화 하기 위해서도 정의한다.

함수의 종류#

함수는 크게 내장 함수사용자 정의 함수로 나뉜다.

내장함수는 프로그래밍에서 자주 사용하는 기능을 미리 만들어놓은 함수이며, 이미 여러분들이 사용해 본 적이 있는 print(), input(), len()… 등이 이에 속한다. 내장함수는 필요할 때 호출해서 사용하면 된다.

사용자 정의 함수는 프로그래머가 필요에 의해서 만든 함수이며 오늘 여러분들이 정의하고 호출할 함수들이 바로 사용자 정의 함수에 속한다.

함수 정의와 호출#

함수를 정의해보고 호출해보자. 함수 정의 형식은 아래와 같다.

def 함수명(매개변수1, 매개변수2, ..., 매개변수n):
    본문 실행문장1
    본문 실행문장2
    ...
    return 리턴값
  • 파이썬에서는 함수를 정의하기 위해 def라는 키워드를 사용한다.

  • def 다음에는 함수명이 오는데 함수명 짓는 규칙은 변수명 짓는 규칙과 똑같다.

  • 함수명() 괄호안에는 매개변수를 적어주며 생략 가능하다. 매개변수는 매개변수 파트에서 자세히 설명한다.

  • def 함수명() 괄호 뒤에는 반드시 콜론(:)을 써야 한다.

  • 함수안에서 실행되는 문장은 반드시 들여쓰기를 해야한다.

  • return은 함수 밖으로 값을 반환할 때 사용하는 키워드이다. 반환 파트에서 자세히 설명한다.

함수 호출 형식은 아래와 같다.

함수명(전달인자1, 전달인자2, ..., 전달인자n)
  • 함수 호출은 정의한 함수를 불러서 사용하는 것을 의미한다.

  • 정의한 함수는 함수명()을 통해 호출한다.

  • 이때 함수명() 괄호안에는 전달인자를 줄 수 있으며 생략 가능하다. 전달인자는 전달인자 파트에서 자세히 설명한다.

심플한 함수 정의#

  • 간단한 예로, hello() 함수를 정의해보자.

  • hello() 함수는 ‘안녕하세요. 반갑습니다.’를 출력하는 함수이다.

  • 함수를 정의(또는 수정)하였다면 함수를 인식하도록 실행시켜 주어야 한다.

  • 함수 정의 파트를 실행시켜도 함수를 호출하는 것은 아니므로 결과가 나오지는 않는다.

def hello():
  print('안녕하세요. 반갑습니다.')
def dragon_treasure():
  print('Gives you my treasure!')
  print('''
                          __/>^^^;:,'
          .    \'    ,      /-.       :,/|/|'
          _______     __/ ^         :,/ \__'
      _ ./_|___|_\. _(~             ;/ /  /'
          \ \   / /    `-\'--._       / / ,<  ___'
          \ \' \' /   ,__.   /=\     /  _/  >|_\'.'
              \ " /     `_ `--------\'    __ / \',\ \\'
              \./   ,_// ,---_____,   ,_  \_  ,| |'
              V     `--\' |=|           \._/ ,/  |'
                          \=\            `,,/   |'
                          \=\            ||    /'
                              \=\____       |\    \\'
                              / \/    `     <__)    \\'
                              | |                    |'
                          ,__\,\                   /'
                          ,--____>    /\.         ./'
                          \'-__________>  \.______/'
      ''')

심플한 함수 호출#

  • 정의한 함수를 실행하려면 함수를 호출해야 한다.

  • 함수를 호출한다는 의미는 함수 정의파트에 있는 본문 실행 문장을 실행시킨다는 것이다.

  • 함수를 호출할 때는 함수명()와 같이 쓴다.

함수명()

😄 아래 output sample과 같이 메뉴를 출력하는 함수 menu_print()를 정의하고 호출해보세요. 줄(===)은 ‘=’*70으로 그리세요.

Output Sample

======================================================================
['햄에그', 'BLT', '치킨샐러드', '리코다치즈', '런치샌드위치', '미니버거']
======================================================================
menulist=['햄에그','BLT','치킨샐러드','리코다치즈','런치샌드위치', '미니버거']

매개변수와 전달인자를 가진 함수 호출과 정의#

매개변수#

def 함수명(매개변수1, 매개변수2, ..., 매개변수n):
    본문 실행문장1
    본문 실행문장2
  • 함수를 정의할 때 함수명() 괄호안에 매개변수를 적어줄 수도 있다. (위에서 봤던 심플한 함수 정의와 같이 전달받아야 할 데이터가 없다면 생략한다.)

  • 매개변수는 함수 안과 함수 밖을 연결해주는 매개체 역할을 해준다고 해서 매개변수이다.

  • 함수 밖에서부터 함수안으로 전달되는 데이터를 받는 변수이다.

  • 전달받아야 할 인자가 하나 이상이라면 매개변수 명을 콤마로 나열한다.

  • 매개변수는 함수 정의파트 본문에서 사용되는 것이 일반적이다.

def hello2(name):
  print(f'{name}님 안녕하세요. 반갑습니다.')
def add(a,b):
  print(f'{a}+{b}의 값은 {a+b}입니다.')

전달인자#

함수명(전달인자1, 전달인자2, ..., 전달인자n)
  • 함수가 매개변수를 가지고 있다면 함수를 호출할 때 함수명() 괄호안에 전달인자를 적어줄 수도 있다. (위에서 봤던 심플한 함수 호출과 같이 전달해야 할 데이터가 없다면 생략한다.)

  • 전달인자는 함수를 호출하면서 함수 정의파트에게 데이터를 전달할 때 사용한다.

  • 전달인자는 파라미터, 인수라고도 불린다.

  • 전달인자가 여러개라면 콤마로 나열한다.

hello2('홍길동')
홍길동님 안녕하세요. 반갑습니다.
  • 전달인자가 두 개라면 매개변수에 차례대로 저장된다.

  • 아래 코드에서 a에는 10이, b에는 20이 전달된다.

add(10, 20)
10+20의 값은 30입니다.

반환(return)#

  • return은 함수 정의파트에서 사용된다.

  • return은 크게 두 가지 역할이 있다.

    • 첫 번째는 함수에서 만들어진 값을 호출자에게 반환 하는 것이다.

    • 두 번째는 함수를 탈출하는 것이다.

  • return이 없어도 함수(정의파트)안의 본문 실행 문장들을 끝까지 실행하면 함수를 빠져나온다. 이때 되돌아오는 위치는 함수 호출코드의 위치이다.

  • 디저트를 반환하는 함수 dessert()를 정의하고 호출해보자.

def dessert(a,b,c):
  print('샤부작~샤부작~')
  print(f'{a+b+c}, 완성되었습니다.')
  return a+b+c
  #return a,b,c
order_dessert ='아이스크림'
dessert("초코", "바닐라", order_dessert)
샤부작~샤부작~
초코바닐라아이스크림, 완성되었습니다.
'초코바닐라아이스크림'
order_dessert = input('Order dessert: ')

print(f'{dessert("초코", "바닐라", order_dessert)}, 받았습니다.')
---------------------------------------------------------------------------
StdinNotImplementedError                  Traceback (most recent call last)
<ipython-input-10-f5ec049b19ec> in <module>
----> 1 order_dessert = input('Order dessert: ')
      2 
      3 print(f'{dessert("초코", "바닐라", order_dessert)}, 받았습니다.')

D:\users\anaconda3\lib\site-packages\ipykernel\kernelbase.py in raw_input(self, prompt)
    853         if not self._allow_stdin:
    854             raise StdinNotImplementedError(
--> 855                 "raw_input was called, but this frontend does not support input requests."
    856             )
    857         return self._input_request(str(prompt),

StdinNotImplementedError: raw_input was called, but this frontend does not support input requests.
  • 함수로부터 반환 받은 값을 위에서와 같이 바로 출력할 수도 있지만, 아래와 같이 변수에 저장할 수도 있다.

r_dessert = dessert("딸기", "바닐라", order_dessert)
print(f'맛있는 {r_dessert}입니다.')
  • return을 만나면 함수를 탈출하기 때문에 return 이후에 어떠한 코드가 있어도 전혀 실행되지 않는다.

def dessert(a,b,c):
  print('샤부작~샤부작~')
  print(f'{a+b+c}, 완성되었습니다.')
  return a+b+c
  print('여긴 무인도야 절대 아무도 안와')

r_dessert = dessert("수박", "키위", order_dessert)
print(f'맛있는 {r_dessert}입니다.')
  • 함수로부터 return이 없는데 반환값을 출력하면 None을 출력한다.

def dessert(a,b,c):
  print('샤부작~샤부작~')
  print(f'{a+b+c}, 완성되었습니다.')

print(f'{dessert("초코", "바닐라", order_dessert)}, 받았습니다.')
r_dessert = dessert("수박", "키위", order_dessert)
print(f'맛있는 {r_dessert}입니다.')

튜플 전달과 반환

  • 함수에서 return으로 값을 반환할때 여러개의 값을 컴마로 나열해서 반환하면 tuple 타입으로 반환한다.

  • 이때 반환받은 값 각각의 항목을 변수에 할당하여 사용할 수 있다.

  • 또한 하나의 변수에 할당하면 튜플타입으로 저장된다.

def mycal(x, y):
  return x+y, x-y

a, b = mycal(100, 50)
print(f'각각의 변수에 저장: {a}, {b}')

c = mycal(200, 30)
print(f'하나의 변수에 저장하면 튜플 형태로 저장:{c}')
print(c[0], c[1])
  • 또한 여러개의 데이터를 함수의 전달인자로 주면 함수의 매개변수는 튜플타입으로 데이터를 받는다.

  • 여러개의 데이터를 받는 매개변수를 하나만 만들고 싶을때는 매개변수 앞에 *를 붙인다.

def myData(*data):
  print(data)

myData(10,20,40,80)

😄 메뉴를 입력받는 함수 order()를 정의하세요. 메뉴는 아래와 같이 여러개 입력받을 수 있습니다. 입력받은 메뉴리스트는 반환합니다.

======================================================================
['햄에그', 'BLT', '치킨샐러드', '리코타치즈', '런치샌드위치', '미니버거']
======================================================================

메뉴를 선택해주세요(종료시 "주문 완료"입력): 치킨샐러드
메뉴를 선택해주세요(종료시 "주문 완료"입력): BLT
메뉴를 선택해주세요(종료시 "주문 완료"입력): 주문 완료
menulist=['햄에그','BLT','치킨샐러드','리코타치즈','런치샌드위치', '미니버거']

# 전체 메뉴를 보여주는 함수
def menu_print():
  print('='*70)
  print(menulist)
  print('='*70)

# 주문한 메뉴를 출력해주는 함수
# order() 함수 정의
def

😄 주문 받은 메뉴의 총합을 계산하는 total_price() 함수를 정의하세요.

pricelist=[5000,7000,6500,6000,6000,3000]

#함수 정의
def

변수의 유효범위(Variable Scope)#

  • 변수는 변수의 유효범위에 따라 전역변수지역변수로 나뉜다.

  • 변수의 유효범위는 변수의 수명 또는 변수가 영향을 미치는 범위를 의미한다.

  • 전역변수의 유효범위는 프로그램 전체이다.

  • 반면, 지역변수의 유효범위는 그 변수를 정의한 함수내에서만 유효하다. 즉, 함수가 호출되었을 때 생성되며 함수를 벗어나면 수명을 다한다.

  • 아래의 예를 통해 전역변수와 지역변수의 개념을 확실히 이해하도록 하자.

지역변수#

  • deposit() 함수와 withdraw() 함수를 정의하고, 각 함수 안에 변수 amount를 정의하였다.

  • 변수 amount는 지역변수이며 자신이 탄생한 함수 안에서는 유효하다.

def deposit():
  amount1 = int(input('입금액: '))
  print(f'{amount1}원이 입금되었습니다.')

def withdraw():
  amount2 = int(input('출금액: '))
  print(f'{amount2}원이 출금되었습니다.')

deposit()
withdraw()
  • 하지만 지역변수 amount1, amount2는 그 변수가 정의된 함수 내에서만 유효하므로 전역에서는 amount1, amount2가 유효하지 않다.

print(f'Global scope: {amount1, amount2}')
  • 또한 amount1는 deposit()의 지역변수이므로 withdraw() 함수에서는 amount1이 유효하지 않다. 이는 amount2도 마찬가지이다.

def deposit():
  amount1 = int(input('입금액: '))
  print(f'{amount1}원이 입금되었습니다.')
  print(f'{amount2}')

def withdraw():
  amount2 = int(input('출금액: '))
  print(f'{amount2}원이 출금되었습니다.')
  print(f'{amount1}')

deposit()
withdraw()

전역변수#

  • 함수밖 전역(Global scope)에서 정의되어 있는 변수를 전역변수라 한다.

  • 전역변수는 유효범위가 프로그램 전체이므로 함수(또는 내부함수)에서도 전역변수를 참조할 수 있다.

def deposit():
  print(f'현재 잔액은 {balance}원입니다.')
  amount1 = int(input('입금액: '))
  print(f'{amount1}원이 입금되었습니다.')

balance = 100000
deposit()
  • 그러나, 아래 코드에서와 같이, 함수안에서 전역변수 수정을 시도하려 했다면 에러가 발생한다.

def deposit():
  print(f'현재 잔액은 {balance}원입니다.')

  # 입금
  amount1 = int(input('입금액: '))
  print(f'{amount1}원이 입금되었습니다.')

  balance += amount1

balance = 100000
deposit()
print(f'현재 잔액은 {balance}원입니다.')
  • 이럴때 앞에서 배웠던 전달인자, 매개변수를 활용하여 값을 전달하고 반환받는 방법을 사용한다.

def deposit(balance):
  print(f'현재 잔액은 {balance}원입니다.')

  # 입금
  amount1 = int(input('입금액: '))
  print(f'{amount1}원이 입금되었습니다.')

  balance += amount1

  return balance

balance = 100000
balance = deposit(balance)
print(f'현재 잔액은 {balance}원입니다.')
  • 함수안에서 전역변수를 정의하거나 전역변수로 지정하려면 global 키워드를 쓸 수 있다.

  • 그러나 함수를 정의할 때에는 일반적으로 “입력값을 받아서 결과를 반환하는 독립적인 블록”으로 설계하기를 권장한다.

  • global 변수를 사용하면 함수가 외부 상태를 바꾸게 되므로,

    • 함수의 동작이 외부 변수에 의존하게 되고

    • 외부 변수의 상태가 언제, 어디서, 왜 바뀌는지 추적하기 어려워진다.

def deposit():
  global balance
  print(f'현재 잔액은 {balance}원입니다.')

  # 입금
  amount1 = int(input('입금액: '))
  print(f'{amount1}원이 입금되었습니다.')

  # 잔액 변화
  balance += amount1

balance = 100000
deposit()
print(f'현재 잔액은 {balance}원입니다.')

마무리#

  • 함수는 프로그램에서 자주 사용되는 소스코드를 만들어두고 필요할 때 사용하는 기능이다.

  • 코드를 구조화 체계화 하기 위해서도 정의한다.

  • 함수를 정의하여 사용하면 다음과 장점을 가질 수 있다.

  • 코드의 간결성: 코드가 중복되지 않고 간결해진다.

  • 코드의 재사용성: 한 번 작성해둔 코드를 여러 번 사용하므로 코드를 재사용할 수 있다.

  • 코드 수정의 용이성: 프로그램 기능을 함수로 나누어 묶기 때문에 코드 수정이 쉽다.

  • 프로그램의 모듈화: 기능별로 함수를 작성하므로 프로그램 모듈화가 증대된다.

  • 함수는 def 함수이름(): 으로 정의하며, 함수이름을 명시하여 호출한다.

  • 전역변수의 유효범위는 프로그램 어디에서든 사용 가능하다.

  • 지역변수의 유효범위는 지역변수가 선언된 함수 내부에서만 사용 가능하다.

  • 전달인자는 함수 외부에서 내부로 값을 전달할 때 사용하며, 함수 호출 시 괄호 안에 기입한다.

  • 매개변수는 함수 정의에서 괄호 안에 기입된 변수를 뜻하며, 전달인자로부터 값을 전달 받아 함수 내부에서 사용된다.

  • return은 함수의 결과를 함수 외부로 반환할 때 사용하는 키워드이다.


F37.101 컴퓨팅 기초: 처음 만나는 컴퓨팅(First Adventures in Computing) 서울대학교 학부대학 변해선