코딩하다 보면 특정 기능을 반복해서 수행해야 할 때가 있습니다. 그때마다 같은 기능을 수행하는 코드를 반복해서 작성한다면 비효율적일 것입니다. 이떄 사용할 수 있는 것이 함수(function)입니다. 함수는 특정 기능을 수행하는 코드의 묶음입니다. 함수를 이용하면 같은 기능을 수행하는 코드를 반복해서 작성할 필요가 없습니다. 또한 코드가 깔끔해지고 한번 만든 코드를 재사용할 수 있어서 코드를 작성하기가 편해집니다.
앞 장에서 파이썬 코드를 작성하면서 이미 몇몇 내장 함수를 이용했습니다. 출력을 위한 print()함수, 데이터 타입을 알기 위한 type()함수 등이 바로 내장 함수입니다. 이번 장에서는 코드의 묶음인 함수를 만들고, 함수를 이용하는 방법을 알아보고 주요 내장 함수의 사용법도 살펴보겠습니다.
함수 정의와 호출
수학 시간에 이미 함수라는 용어에 대해 배웠을 것입니다. 수학에서 말하는 함수는 다음과 같이 표현할 수 있습니다.
y=f(x)
x에 숫자를 넣으면 f(x)에서 연산을 수행해 계산 결과를 y에 얻을 수 있습니다. 만약 함수가 y=x^2 와 같이 정의됐다면 입력값 x에 대해 제곱을 수행한 결과값을 얻을 수 있습니다.
함수의 기본 구조
프로그래밍에서의 함수도 수학의 함수와 유사합니다. 함수는 특정 기능을 수행하는 코드의 묶음이라고 했습니다. 수학 함수에서 입력값을 프로그래밍 함수에서는 인자라고 합니다. 프로그래밍에서는 이 인자를 통해 함수에 값을 전달할 수 있습니다. 수학 함수에서 계산된 함수값을 프로그래밍 함수에서는 반환값이라고 합니다. 단, 프로그래밍의 함수는 수학 함수와 달리 인자와 반환값이 없을 수도 있습니다.
함수를 이용하려면 먼저 함수를 정의(함수 만들기)해야 합니다. 함수를 정의한 후에야 함수를 호출(정의된 함수 부르기) 할 수 있습니다. 함수를 한 번 정의하고 나면 함수는 필요할 때마다 몇 번이고 호출할 수 있습니다.
함수의 구조는 다음과 같습니다.
def 함수명([인자1, 인자2, ... , 인자n]) <코드 블록> [return <반환값> |
함수는 def 키워드로 시작합니다. 그 뒤에 프로그래머가 정의한 함수명(함수이름)을 입력합니다. 함수명은 주로 영문 알파벳 소문자로 구성되며 가독성을 높이기 위해 밑줄(_)을 이용하기도 합니다. 함수명을 입력한 후에는 소괄호와 콜론을 입력합니다. 위의 구조에서 대괄호 안의 내용은 필요에 따라 쓸 수도 있고, 쓰지 않을 수도 있습니다. 함수에서 사용할 인자가 있으면 소괄호 안에 인자를 입력합니다. 인자를 여러 개 입력할 수 있는데 인자와 인자 사이는 콤마로 구분합니다. 함수에서 사용할 인자가 없으면 소괄호만 입력합니다. 소괄호 다음에는 콜론을 입력합니다. 그 이후 줄을 바꾸고 들여쓰기를 한 후에 <코드 블록>에 코드를 입력합니다. 반환값이 있으면 마지막 줄에 return<반환값>을 입력하고 없으면 아무것도 입력하지 않습니다.
함수를 정의한 후 정의된 함수를 호출해야 함수가 실행됩니다. 함수를 호출할 때는 함수를 정의할 때 지정했던 인자도 함께 써야합니다. 이때 인자의 개수와 순서는 같아야 합니다. 만약 함수를 정의할 때 인자가 없었으면 함수를 호출할 때 소괄호 안에 아무것도 입력하지 않습니다. 다음은 앞에서 정의한 함수를 호출하는 코드 구조입니다.
함수명([인자1, 인자2, ... , 인자n]) |
인자도 반환값도 없는 함수
함수는 전달할 인자와 반환값의 유무에 따라 다양한 구조로 만들 수 있습니다. 먼저 인자도 없고 반환값도 없는 가장 간단한 구조의 함수를 살펴보겠습니다.
In : def my_func(): print("My first function!") print("This is a function.") |
위와 같이 함수를 정의하고 실행하면 아무 일도 일어나지 않습니다. 오류가 발생하지 않고 아무 일도 일어나지 않는다면 함수가 잘 정의된 것입니다. 만약 오류가 발생한다면 잘못된 곳을 수정한 후 다시 실행합니다.
함수를 정의한 후에 호출해야 비로소 함수가 실행됩니다. 앞에서 정의한 my_func() 함수에는 인자가 없기 때문에 다음과 같이 함수명과 소괄호만 입력해 함수를 호출합니다.
In : my_func() Out : My first function! This is a function. |
인자는 있으나 반환값이 없는 함수
다음으로 인자는 있지만 반환값이 없는 함수를 정의하고 호출하는 예를 살펴보겠습니다. 인자가 있는 함수의 예를 살펴보면 함수의 진가를 알 수 있을 것입니다.
먼저 인자(여기서는 문자열) 하나를 넘겨받아 출력하는 함수를 정의하겠습니다.
In : def my_friend(friendName): print("{}는 나의 친구입니다..".format(friendName)) |
이제 정의한 함수에 인자를 각각 입력해서 호출해 보겠습니다.
In : my_friend("철수") my_friend("영미") Out : 철수는 나의 친구입니다. 영미는 나의 친구입니다. |
위의 코드에서 함수를 두 번 호출했는데 각각 인자를 다르게 입력해 출력 결과가 다르게 나왔습니다. 위에서 보듯이 함수에 인자를 이용하면 인자에 따라 다른 결과를 얻을 수 있습니다.
함수에서 인자는 하나일 수도 있고 여러 개일 수도 있습니다. 다음은 인자가 세 개인 함수입니다.
In : def my_student_info(name, school_ID, phoneNumber): print("---------------------") print("- 학생이름:", name) print("- 학급번호:", school_ID) print("- 전화번호:", phoneNumber) |
함수를 정의할 때 세 개의 인자를 넘겨볻도록 만들었기 때문에 호출할 때도 다음과 같이 세 개의 인자를 입력해서 함수를 호출합니다.
In : my_student_info("현아", "01", "01-235-6789") |
앞에서 정의한 my_student_info() 함수를 수정하면 이 함수를 호출하는 ㅁ모든 코드에 적용됩니다. 다음은 my_student_info() 함수의 출력 양식을 수정한 함수입니다.
In : def my_student_info(name, school_ID, phoneNumber): print("*********************") print("* 학생이름:", name) print("* 학급번호:", school_ID) print("* 전화번호:", phoneNumber) |
이제 앞에서 입력한 인자를 변경 없이 그대로 입력해서 my_student_info() 함수를 다시 호출하겠습니다.
In : my_student_info("현아", "01", "01-235-6789") |
함수를 호출한 결과를 보면 수정된 내용이 잘 반영됐음을 확인할 수 있습니다. 이처럼 함수를 이용하면 코드의 작성과 수정이 편리합니다.
인자도 있고 반환값도 있는 함수
다음으로 인자를 받아서 처리한 후에 값을 반환하는 함수에 대해 알아보겠습니다. 이를 위해 다음과 같이 가로와 세로 길이 인자 두 개를 받아서 넓이를 계산한 후 그 결과를 반환하는 함수를 정의하겠습니다. 반환값이 있으므로 'return<반환값>'을 이용합니다.
In : def my_calc(x,y): z=x*y return z |
이제 인자를 입력해서 함수를 호출하면 다음과 같이 함수값(넓이)를 출력합니다.
In : my_calc(3,4) Out : 12 |
앞에서는 문자열이나 숫자가 함수의 인자로 들어가는 예를 살펴봤습니다. 파이썬에서는 함수의 인자로 리스트, 세트, 튜플, 딕셔너리도 사용할 수 있습니다. 다음은 리스트를 인자로 갖는 함수입니다.
In : def my_student_info_list(student_info): print("********************") print("* 학생이름:", student_info[0]) print("* 학급번호:", student_info[1]) print("* 전화번호:", student_info[2]) print("********************") |
위 함수의 인자는 리스트이므로 다음과 같이 인자를 리스트로 입력해서 함수를 호출합니다.
In : student1_info=["현아", "01", "01-235-6789"] my_student_info_list(student1_info) Out : ******************** * 학생이름: 현아 * 학급번호: 01 * 전화번호: 01-235-6789 ******************** |
위처럼 리스트를 변수에 넣은 후에 이것을 함수의 인자로 넣지 않고 다음처럼 리스트를 바로 인자로 지정할 수도 있습니다.
In : my_student_info_list(["진수", "02","01-987-6543"]) Out : ******************** * 학생이름: 진수 * 학급번호: 02 * 전화번호: 01-987-6543 ******************** |
변수의 유효 범위
함수 안에서 정의한(혹은 생성한) 변수는 함수 안에서만 사용할 수 있습니다. 즉, 함수 안에서 생성한 변수는 함수를 호출해 실행되는 동안만 사용할 수 있고 함수 실행이 끝나면 더는 사용할 수 없습니다. 함수 안에서 정의한 변수는 함수 영역 안에서만 동작하는 변수임므로 지역 변수(local variable)라고 합니다. 지역 변수는 함수가 호출될 때 임시 저장 공간(메모리)에 할당되고 함수 실행이 끝나면 사라집니다. 또한 다른 함수에서 같은 이름으로 변수를 사용해도 각각 다른 임시 저장 공간에 할당되므로 독립적으로 동작합니다. 지역 변수의 상대적인 개념으로 함수 밖에서 생성한 변수인 전역 변수(global variable)가 있습니다. 지역 변수는 함수 안에서만 사용할 수 있지만 전역 변수는 코드 내 어디서나 사용할 수 있습니다.
변수를 정의할 때 변수가 저장되는 공간을 이름 공간이라고 하는데 변수를 함수 안에서 정의했느냐, 함수 밖에서 정의했느냐에 따라 코드 내에서 영향을 미치는 유효 범위(scope)가 달라집니다. 지역 변수를 저장하는 이름 공간을 지역 영역(local scope)이라고 하고 전역 변수를 저장하는 이름 공간을 전역 영역(global scope)이라고 합니다. 또한 파이썬 자체에서 정의한 이름 공간을 내장 영역(built-in-scope)이라고 합니다. 함수에서 어떤 변수를 호출하면 지역 영역, 전역 영역, 내장 영역 순서대로 변수가 있는지 확인합니다. 이를 스코핑 룰(Scoping rule) 혹은 LGB 룰(Local/Global/Built-in rule)이라고 합니다.
함수를 작성할 때 지역 변수와 전역 변수의 이름이 다르다면 문제가 되지 않지만 만약 동일한 변수명을 지역 변수와 전역 변수에 모두 이용했다면 이것을 이용할 때 스코핑 룰에 따라 변수가 선택됩니다. 다음은 하나의 코드에서 같은 이름의 변수를 지역 변수와 전역 변수로 모두 사용한 예입니다.
In : a=5 #전역 변수 def func1(): a=1 #지역변수. func1()에서만 사용 print("[func1] 지역 변수 a=", a) def func2(): a=2 #지역변수. func2()에서만 사용 print("[func2] 지역 변수 a=", a) def func3(): print("[func3] 전역 변수 a=", a) def func4(): global a #함수 내에서 전역 변수를 변경하기 위해 선언 a=4 #전역 변수의 값 변경 print("[func4] 전역 변수 a=", a) |
위 코드에서 함수 밖에서 정의된 전역 변수 a에는 5를 할당했습니다. 함수 func1()과 func2() 안에서 정의된 지역 변수 a에는 각각 1과 2를 할당하고 출력했습니다. 함수 func3()에서는 지역 변수 a를 정의하지 않고 a를 출력했습니다. 이때는 전역 변수 a를 가져와서 출력합니다. 전역 변수는 코드 내 어디서나 사용할 수 있으므로 함수 안과 함수 밖에서 모두 이용할 수 있습니다. 함수 func4()에서도 지역 변수 a를 정의하지 않고 a를 이용했습니다. 단, 함수 func4()에서는 전역 변수 a의 값을 변경했습니다. 함수 안에서 전역 변수의 내용을 변경할 때는 'global 전역 변수명'을 먼저 선언해야 전역 변수의 내용을 변경할 수 있습니다.
이제 앞에서 정의한 각각 함수를 호출해 각 함수에서 어떤 a가 사용되는지 살펴보겠습니다.
In : func1() func2() print("전역 변수 a=", a) Out : [func1] 지역 변수 a=1 [func2] 지역 변수 a=2 전역변수 a=5 |
위 출력 결과에서 함수 안에서 정의된 지역 변수는 같은 이름의 전역 변수보다 먼저 참조되고 함수가 끝나면 그 효력이 즉시 가라지는 것을 알 수 있습니다. 또한 함수를 호출하지 않고 변수를 이용하면 전역 변수를 참조하는 것을 확인할 수 있습니다.
In : func3() func4() func3() Out : [func3] 전역 변수 a=5 [func4] 전역 변수 a=4 [func3] 전역 변수 a=4 |
함수 호출 결과를 비교해 보면 함수 func4() 호출로 전역 변수 a의 값이 변경됐음을 알 수 있습니다.
출처 : 데이터분석을 위한 파이썬 철저 입문 中