▼2020년/파이썬 기초

[Python] 파이썬에서의 함수

ITISIK 2020. 1. 23. 14:33
반응형

함수란?

  중학생들이 수학을 포기하는 첫 번째 시점이 함수라서, 이번 글은 최대한 쉬운 이해를 중점으로 작성하려고 한다. 그러니 당신이 수포자이거나 수학에서의 함수를 잘 모른다고 할지라도 겁먹지 말고 이 글을 통해 함수의 개념에 대해서 공부할 수 있었으면 좋겠다.

 

  우리가 살아가고 있는 세상은 함수로 가득하다. 지금 필자가 타이핑하면서 사용하고 있는 키보드도 일종의 함수이다. 키보드에서 'Zㅋ'키를 누르면 ㅋ이 입력되는 것이 바로 그것이다.

 

  수학에서의 함수는 영어로 Function이다. 그리고 Function의 첫 번째 의미는 '기능'이다. 따라서 함수는 어떠한 기능을 수행하는 것이라고 이해하면 된다.

 

  가령, 필자가 키보드에서 'Zㅋ'키를 눌렀는데 숫자 '5'와 같이 엉뚱한 글자가 찍힌다면, 사람들은 이 키보드를 가리켜 '고장났다.'고 할 것이다. 왜냐하면 본래 'Zㅋ'키는 'ㅋ' 혹은 'z(Z)'를 입력하기 위한 목적으로 만든 키인데 그 역할을 제대로 수행하지 못하기 때문이다.

 

  함수가 이러하다. 세상에 존재하는 모든 함수는 그 목적을 가지고 만들어 진다. 예를들어 길거리 자판기의 '설탕커피' 버튼은 설탕커피를 제조하기 위해서 만들어진 버튼이고 함수이다. 스마트 폰의 '전원'버튼은 전원을 켜고 끄기 위해서 만들어진 버튼이고 함수인 것이다.

 

  위 다섯 문단을 요약하면 함수는 입력값과 출력값이 존재하며 특정한 목적을 달성하기 위해 만들어진 것이다.

 

굳이 함수를 사용해야하는 이유

  결국 함수는 (목적을 이루기 위한) 어떤 기능을 가지고 있는데, 이런 기능이 단순할 때는 함수를 이용하지 않아도 괜찮지만, 기능을 구현하는 코드가 길어지고 복잡해질수록 사용할 때마다 매번 코드를 입력하고 수행하는 것이 굉장히 번거로운 작업이 된다.

 

  또 기능을 단위별로 함수로 만들어두면, 각각의 함수가 하는 일이 명확해지고 데이터의 흐름이나 작업의 경로가 정리되어 보이기 때문에 코드 작성과 수정, 대체, 성능개선 등도 용이해진다.

 

  따라서 그 목적과 사용처가 분명한 경우 함수로 한 번 정의해두면 언제 어디서든지 함수를 사용하여 쉽게 문제를 해결할 수 있다는 점에서 함수는 꼭 필요하다고 할 수 있다.

 

함수 선언과 그 생김새

  함수를 사용하기 위해서는 우선 해당 함수의 이름은 무엇이고, 하는 일은 어떻게 되는지를 정의 해야한다. 정의를 영어로 Definition이라고 하는데, 여기서 앞자를 따 def라는 키워드를 함수정의(선언)시 사용하게 된다. 아래의 코드를 참고하자.

def 함수의_이름(매개변수):
    함수 호출시 수행할 코드
    return 반환할_값

# 함수의 이름은 변수와 마찬가지로 띄어쓰기 없이 작성해야 한다.
# 매개변수는 0개 이상 존재한다. 즉 없을 수도 있다.
# return이라는 키워드로 특정값을 반환하면서 함수를 종료시키는 것이고, 생략시 반환값이 없다.

  이러한 함수 내부에서는 이전에 배웠던 if, while, for문 등을 자유롭게 사용하여 원하는 기능을 만들어두면 유용하다.

  두 수를 입력받아 두 수를 더하고 그 값을 출력시키는 함수를 작성해보자.

def my_sum(a ,b):
    return a + b

my_sum(9, 2)

  위 함수를 호출하면서 a, b의 위치에 적절한 수를 넣어주면 아래와 같이 작동된다.

 

  이렇게 return으로 반환되는 값은 아래와 같이 새로운 변수에 그 값을 할당시켜 사용할 수도 있다.

sum_val = my_sum(9, 2)
sum_val

  이쯤에서 함수의 이해를 방해하는 한 가지가 있는데 바로 같은 것을 상황에 따라 이름을 다르게 부르는 매개변수와 인수(인자)다. 너무 겁먹지는 말자. 사람과 동일하다고 생각하면 된다. 친구들 사이에서는 별명으로, 직장에서는 존칭과 직함으로, 부모님에게는 아들, 딸로 불리우는 것과 같은 이치라고 생각하자.

  함수를 선언할 때, 더 엄밀히 말하면 전달받은 값을 사용할 때 이용되는 것을 매개변수라고 하며, 함수를 사용하고자 할 때, 더 엄밀히 말하면 함수를 호출할 때 전달해주는 값을 인수(인자)라고 한다. 이를 구분하지 않고 혼용하는 분들도 많지만, 그렇다고 공부를 엉성하게 할 수는 없으니 처음 배울 때 정확하게 공부하는 것이 중요하다고 생각한다.

 

함수의 입력값

  함수의 입력값의 가능한 개수는 0개 이상이다.

def func_input0():
    return '문제없음'
def func_input5(num1, num2, num3, num4, num5):
    return num1 + num2 + num3 + num4 + num5

 

함수의 출력값

  함수의 출력값은 return에 의해서 결정된다. return문이 없는 함수는 출력값이 존재하지 않는(None) 함수인 것이다. 때문에 출력값의 개수는 0개 또는 1개이다. return문에서 가장 중요한 사실은, 반환값은 단 한 가지라는 점과, 함수 내부에서 return을 만나면 이하 코드는 판단하지 않고 즉시 함수가 종료된다는 점이다.

def func_output0():
    print('print 함수가 수행된 것이지, 반환값(출력값)이 있는게 아니다.')
def func_output1():
    return 10

# 아무값을 입력받지 않아도, 출력값이 10으로 고정되어 있으므로, 출력값은 존재하는 것이다.(10으로)

  만약 2개 이상 출력시키고 싶다면, return 문 뒤에 콤마로 구분하여 여러개를 작성해주면 된다. 다만, 튜플형으로 묶여서 출력되기 때문에 유의하여야 한다.

def func_output3():
   return 1, 2, 3

 

함수 호출시 매개변수 지정

  함수를 호출할 때 전달할 인자가 있는 경우, 함수 정의 때 작성해준 순서대로 해당 매개변수에 값이 대입되는 것이 기본값인데, 특정 매개변수에 원하는 값이 할당되도록 할 수 있다.

def my_calc(num1, num2, num3):
    return num1 + num2 * num3

my_calc(1, 2, 3)
my_calc(num3 = 1, num2 = 2, num1 = 3)

 

함수 매개변수의 개수를 특정할 수 없는 경우

  예를 들어 우리가 계산기 프로그램을 만든다고 생각해보자. 사용자가 숫자 두 개를 더할지 백개를 더할지 알 수 없는 노릇이다. 이렇게 그 개수(길이)를 특정할 수 없는 것을 가리켜 가변길이(변할 수 있는 길이)라고 한다. 가변길이 매개변수의 경우 asterisk( * )를 이용해서 처리할 수 있다.

※ 아래 코드에서 args란, 위에서 배운 arguments의 약어로 프로그래밍에서 통용되는 약어이다. 굳이 args로 할 필요는 없다.

def my_times(*args):
    result = 0
    for number in args:
        result *= number
    return result

my_times(5, 4, 3, 2, 1)
my_times(5, 4, 3, 2, 1, 5)

asterisk를 사용한 매개변수를 사용하더라도 다른 매개변수를 추가로 사용할 수 있다. 대신 아래와 같이 *args 매개변수를 뒤쪽에 작성해주어야 한다.

def multi_func(operator, *args):
    if(operator == '+'):
        result = 0
        for number in args:
            result += number
        return result
    elif(operator == '-'):
        result = 0
        for number in args:
            result -= number
        return result
    elif(operator == '*'):
        result = 1
        for number in args:
            result *= number
        return result
    elif(operator == '/'):
        result = args[0]**2
        for number in args:
            result /= number
        return result

 

입력값의 개수과 출력값의 개수에 따른 생김새 정리

  파이썬의 함수에서 입력값의 개수는 최소 0개에서 최대 무한대개가 가능하다. 그리고 출력값은 최소 0개에서 최대 1개만 가능하다. 자료형에 따라서 2개 이상'처럼' 보일 수는 있지만, 실제로 함수에서 2개 이상의 출력값을 가질 수는 없다. 아래의 표를 통해서 그 호출시 생김새를 익혀두자.

 

구 분 입력값
0개 1개 2개 이상
출력값 0개 None my_func() my_func(agrs) my_func(args1, args2, ...)
1개 Result Value

 

Key-Value Pair를 만들어주는 키워드 파라미터

  이전에 공부한 딕셔너리 자료형에 대해서 공부했던바 있다. 딕셔너리 자료형으로 변수를 만들어주기 위해서는 아래와 같이 할당했어야 했다.

my_info = {'name' : 'ITisik', 'age' : 27, 'blog' : 'naver/tistory'}

  하지만 파이썬에는 asterisk 2개를 활용한 키워드를 활용하여 아래와 같이 더 간단하게 키-벨류 쌍을 만들어줄 수 있다.

  * Key-Value 쌍을 지어줄때 콜론( : )이 아닌 등호( = )로 해준다는 점과 키에 해당하는 값들을 작은따옴표( ' )로 감싸지 않는다는 점이 특징이다.

def make_dic(**kwargs):
    return kwargs

my_info = make_dic(name = "ITisik", age = 27, blog = 'naver/tistory')
my_info['age']
my_info

 

함수에서 2개 이상의 값을 출력하고 싶을 때

  결론부터 말하면 불가능하다. 그 이유는 간단하다. 컴퓨터는 특정 명령에 대해서 명확하고 깔끔한 답을 가져와야 하는데, 만약 함수에서의 출력값이 두 개 이상이 되는 경우 해당 함수에 대해 명확하고 깔끔한 답을 낸다고 할 수 없기 때문이다.(답이 2개이기 때문에.) 실제 수학에서의 함수도 특정 입력값에 대한 명확한 한 개의 결과값이 있어야 한다.

 

  그렇다고 아예 불가능 한 것은 아니고 인간이 충분이 응용할 수 있을 만한 범위에서 가능하다. 바로 return문에서 콤마(,)를 활용하여 튜플형으로 반환하는 방법이다. 아래의 예시코드를 보자.

def multi_result(num1, num2, num3):
    return num1+num2, num2+num3

multi_result(1, 2, 10)

  이와같이 튜플이라는 하나의 값 속에 여러개의 결과를 내포하는 방식으로는 출력이 가능하다. 다만 return 문을 두개 반복해서 사용한다든가하는 형태로 결과값을 2개 이상 출력하는 것은 불가능 하다는 점을 짚고 넘어가겠다. 왜냐하면 첫 번째 return문을 만남과 동시에 해당값을 반환하고 함수가 종료되기 때문이다. 이러한 return 문의 성질을 이용해서 특정 상황시(if문 활용) return을 실행시킴으로서 함수를 종료시킬 수도 있다.

def end_game(num):
    if(num % 2 == 0):
        return
    print('입력하신 수는 홀수입니다.')


함수의 매개변수에 초기값 설정해두기

  함수를 선언할 때, 마지막 매개변수에 초기값을 설정해두면 나중에 함수 호출(사용) 시 좀 더 편할 수 있다. 예를들어 고등학교에서 성적을 관리하는 프로그램을 만들고자 하는데, 대부분의 학생이 18세라는 가정을 하고, 아래의 코드를 보자.

def grade_program(name, point, age):
    grade = ''
    if(point >= 90):
        grade = 'A'
    elif(point >= 75):
        grade = 'B'
    elif(point >= 60):
        grade = 'C'
    else:
        grade = 'F'
    return name, age, grade

grade_program('ITisik', 88, 18)
grade_program('홍길동', 95, 18)
grade_program('홍길서', 55, 19)
grade_program('홍길남', 74, 18)

  위와같이 대부분의 학생이 18살인데도 불구하고 매번 18이라는 나이를 입력해주어야 하는 번거로움이 있다. 이럴 때 아래와 같이 매개변수에 초기값을 설정해두면 편리하다.

def grade_program(name, point, age = 18):
    grade = ''
    if(point >= 90):
        grade = 'A'
    elif(point >= 75):
        grade = 'B'
    elif(point >= 60):
        grade = 'C'
    else:
        grade = 'F'
    return name, age, grade

grade_program('ITisik', 88)
grade_program('홍길동', 95)
grade_program('홍길서', 55, 19)
grade_program('홍길남', 74)

  다만 이렇게 초기값 설정을 해줄 경우, 해당 매개변수 함수의 매개변수 중에서 가장 뒤에 와 있어야 좋다. 그렇지 않으면 어떤 값을 생략하는 것인지 애매모호해져서 직접 매개변수를 지정해주어 호출해야하는 번거로움이 생기기 때문이다.

 

전역변수와 지역변수

  '전역'변수는 '전'체 영'역'의 변수라고 생각하면 되고, '지역'변수는 국소'지역'의 변수라고 생각하면 된다. 파이썬을 포함한 프로그래밍 언어에서는 이 전역변수와 지역변수를 구분짓는 것이 매우 중요하다. 전역변수는 해당 프로그램 내부 어디에서든지 부르고 사용할 수 있는 변수이며, 지역변수는 해당 변수가 생존할 수 있는 범위(Scope)에서만 부르고 사용할 수 있는 변수이다. 아래의 작은 프로그램을 보고 전역변수와 지역변수에 대해서 익힐 수 있었으면 좋겠다.

# 프로그램 시작
result = '문장' #전역변수인 result

def scope_func(num1, num2):
    sum_num = num1 + num2
    if(num1 > num2):
        result = '앞에 입력한 수 ' + str(num1) + '이/가 큰 수 입니다.' #지역변수인 result
    else:
        result = '뒤에 입력한 수 ' + str(num2) + '이/가 큰 수 입니다.' #지역변수인 result
    return sum_num, result
# 프로그램 종료

result
sum_num
scope_func(50, 100)
scope_func(500, 100)
result
sum_num

  함수 내부에서 선언한 sum_num이라는 변수는 scope_func() 함수 안에서만 선언/할당/호출할 수 있는 변수로, 함수가 종료된 뒤에는 아무리 호출을 해도 없는 값(not defined)이라며 오류를 낸다.

 

  result의 경우, 가장 첫 줄에 선언된 result는 전역변수이고, 함수 내부에서 사용되는 result는 지역변수이다. 그리고 함수 내부에서 할당한 result의 경우, 전역변수가 아닌 지역변수이기 때문에 함수 밖에 있는 변수 result의 값('문장')에는 영향을 미칠 수 없다. 만약 전역변수에 해당하는 result의 값을 변경하려면 아래와 같이 작성하는 것이 추천된다.

# 프로그램 시작
result = '문장' #전역변수인 result

def scope_func(num1, num2):
    sum_num = num1 + num2
    if(num1 > num2):
        result = '앞에 입력한 수 ' + str(num1) + '이/가 큰 수 입니다.' #지역변수인 result
    else:
        result = '뒤에 입력한 수 ' + str(num2) + '이/가 큰 수 입니다.' #지역변수인 result
    return sum_num, result
# 프로그램 종료

result = scope_func(50, 100)[1]
result
result = scope_func(500, 100)[1]
result

  만약 함수 내부에서 함수 밖에 있는 전역변수를 호출하고 싶다면 global 키워드를 아래와 같이 이용해야 한다.

global_str = '문장'

def global_func(str):
    global global_str #전역변수 중에서 global_str을 찾아 당겨온다.
    global_str = str #당겨온 전역변수 global_str에 입력받은 str값을 할당.

global_func('바꾸어 봅시다')
global_str

  다만 함수는 전체 프로그램에 대해서 독립적일 수록 좋으므로, global 키워드를 활용하여 전역변수를 직접 건드리는 함수는 되도록이면 정의하지 않는 것이 좋다.

 

람다식(익명함수)

  람다식은 함수를 정의하여 사용할 수 없는 상황이나, 코드에 간단하게 넣어 작동하도록 하고 싶은 경우에 사용한다. 이름 그대로 함수(기능)는 있으나, 그 이름이 없다. 이미 함수 파트의 글이 충분히 길어졌기 때문에 아래의 사용예를 통해서 간단하게 그 동작 원리만 파악하고 마치는 것으로 하겠다.

print((lambda num1, num2: num1 + num2)(12, 19))
add = lambda a, b: a + b
result = add(12, 19)
result
print((lambda num1, num2 : num1 if num1 % 2 == 0 else num2)(10, 20))
print((lambda num1, num2 : num1 if num1 % 2 == 0 else num2)(11, 21))

 

 

 

이상으로 파이썬에서의 함수에 대해서 알아보았습니다. 짧지 않은 글 읽어주셔서 감사드리며, 다음 포스트에서는 파이썬에서 사용자에게 입력받는 방법, 출력하는 방법에 대해서 공부하도록 하겠습니다.

 

반응형