프로그램은 명령문의 합성으로 구현된다. 많은 프로그램은 몇 백 또는 몇 천 줄의 명령문으로 구성되며, 경우에 따라 몇 십만, 몇 백만. 심지어 천만 줄 이상의 명령문으로 구성된 프로그램도 있다.
몇 백 줄 이상의 명령문으로 구성된 프로그램을 구현하다 보면 특정 기능을 수행하는 명령문을 반복해서 사용하곤 한다. 또한 프로그램의 소스코드를 여러 개의 소스코드 파일로 나누어 작성하고 관리할 필요성도 대두된다. 이때 함수와 모듈을 활용한다.
여기서는 먼저 함수에 대해 이야기하고 이어지는 장에서 모듈을 소개한다.
10.1함수 호출과 표현식¶
함수function는 간단히 말해 명령문에 붙인 이름이다.
예를 들어 아래 코드를 실행하면 "함수란 특정 명령문을 대신한다." 라는 문장이 화면에 출력된다.
print('함수란', '특정 명령문을 대신한다.')함수란 특정 명령문을 대신한다.
print() 함수가 대신하는 명령문,
즉 print라는 이름이 붙은 명령문이 작동하여 인자로 지정된 아래 두 문자열을
공백을 사이에 두고 연속적으로 화면에 출력한다.
첫째 인자:
함수란둘째 인자:
특정 명령문을 대신한다.
print라는 이름이 붙은 명령문이 정확히 어떻게 구현되었는지 사용자는 쉽게 알지 못하며,
또 굳이 알 필요도 없다.
화면에 문자열 등의 값을 출력하고 싶을 때 print() 함수를 사용한다는 사실만 알면 된다.
함수는 아래 형식의 함수 호출function call을 통해 활용된다.
함수이름(인자1, 인자2, ..., 인자n)함수 호출에 필요한 인자의 수는 함수의 정의에 의존한다.
print() 함수는 0 개 이상의 인자를 사용할 수 있다.
int(), float() 등의 형변환 함수는 0개 또는 하나의 인자를 사용한다.
int("3")3float("3.14")3.14인자를 사용하지 경우에도
함수 호출은 열고닫기 소괄호 ()를 반드시 사용해야 한다.
예를 들어 int() 함수와 float() 함수를 인자 없이 호출하면 각각 0과 0.0을 계산한다.
int()0float()0.0반면에 print() 함수를 인자 없이 호출하면 아무 것도 출력되지 않는다.
print()
함수 호출 표현식과 값
함수 호출 표현식은 함수 호출 형식으로 값을 값을 표현하는 표현식이다.
예를 들어 int(3.14)는 정수 3을,
float('3.14')는 부동소수점 3.14를,
type(3.14)는 부동소수점의 자료형인 float를,
type('3.14')는 문자열의 자료형인 str를 표현한다.
사실 함수 호출 표현식이 표현하는 값은 함수를 호출하여 실행했을 때 계산되는 값이다.
int(3.14)3float('3.14')3.14type(3.14)floattype('3.14')str함수 호출 표현식은 함수에 의해 계산되는 값을 대신하여 필요에 따라 활용될 수 있다.
예를 들어 아래 코드는 int() 함수가 계산한 결과를 제곱한다.
y = int(3.14)
y**29반면에 아래 코드는 type() 함수에 의해 계산된 자료형에 따라
다른 명령문을 실행하도록 하였다.
변수 x가 가리키는 값이 문자열이기에 type(x) == str이 참이되어
print(x * 2)가 실행된다.
x = '3.14 '
if type(x) == str:
print(x * 2)
else:
print(x / 2 )3.14 3.14
10.2함수 선언¶
함수는 아래 형식으로 선언된다.
def 함수이름(매개변수1, 매개변수2, ...):
명령문def 키워드로 시작하는 줄은 함수의 기본 정보를 담은 헤더header이고
나머지는 함수의 본문body이다.
함수의 본문은 함수가 호출되었을 때 실행되어야 하는 명령문을 포함한다.
함수를 정의할 때 다음 세 가지 사항에 주의한다.
함수 이름과 매개변수 이름: 변수 이름 짓기와 동일한 조건을 따른다.
매개변수의 종류와 수: 함수를 정의하는 사용자가 정한다.
함수 헤더의 끝에 위치한 콜론
::함수 헤더의 끝을 나타낸다.
함수 본문 명령문은 들여쓴다. 들여쓰기는 보통 Tab 키를 이용한다.
10.2.1매개변수와 인자¶
매개변수parameter는 함수의 본문에서만 사용되는 변수이며
함수를 호출할 때 사용하는 인자argument를
함수 본문의 명령문에 전달한다.
예를 들어 아래 코드는 정수 또는 부동소수점 두 개가 주어지면
두 수의 합을 계산하는 함수 myAdd를 정의한다.
두 개의 수를 인자로 받아 합을 계산해야 하기에 두 개의 매개변수를 사용한다.
left매개변수: 덧셈 연산의 첫째 인자right매개변수: 덧셈의 연산의 둘째 인자
def myAdd(left, right):
sum_ = left + right
return sum_이제 myAdd() 함수를 두 개의 인자와 함께 호출하면 두 인자의 합을 계산한다.
예를 들어 아래 코드는 -2와 5의 합을 계산한다.
myAdd(-2, 5)310.2.2함수 호출과 반환값¶
myAdd(-2, 5) 가 호출되었을 때 파이썬 실행기 내부에서 실제로 실행되는 명령문은
두 단계로 구성된다.
첫째, 매개변수 각각에 대해 주어진 인자의 순서대로 변수 할당 명령문이 실행된다.
left = -2
right = 5left와 right 두 매개변수가 함수의 본문에서 사용될 때
이렇게 할당된 값을 이용한다.
이런 의미에서 매개변수가 인자를 함수의 본문에 전달한다고 말한다
둘째, myAdd() 함수의 본문에 사용된 명령문이 차례대로 실행된다.
sum_ = left + right
return sum_즉 sum_ = left + right 명령문이 실행되어 sum_ 변수에 정수 3이 할당된다.
끝으로 return sum_ 명령문이 실행된 후에 바로 함수 호출의 실행 과정이 종료된다.
함수 반환값
함수는 호출되면 앞서 설명한 대로 매개변수에 지정된 인자가 할당된 상태에서 본문 명령문이 차례대로 실행된다. 그러다가 아래 모양의 반환 명령문이 실행되는 순간 바로 함수의 실행이 종료된다.
return 표현식그런데 함수의 실행이 완전히 종료되기 전에 return 명령문에 지정된 표현식이
표현하는 값이 반환값으로 지정된다.
예를 들어 myAdd(-2, 5)가 호출되면 sum_ 변수에 할당된 3이 함수의 종료와 함께
반환값으로 지정된다.
함수 호출 표현식은 이때 지정된 반환값을 대신하여 언제든지 재활용될 수 있다.
예를 들어 아래 코드는 3을 대신하여 myAdd(-2, 5)가 변수 할당에 활용된다.
sum_of_minus2_5 = myAdd(-2, 5)반면에 아래 코드는 반환값을 바로 곱셈 연산에 활용한다.
myAdd(-2, 5) * 39이처럼 myAdd(-2, 5)과 같은 함수 호출 표현식은 해당 함수 호출의 반환값과 동등하게 사용된다.
return ... 명령문의 위치
함수의 본문이 실행되는 도중에 return ... 명령문이 실행되는 순간
반환값이 지정되면서 동시에 함수의 실행이 중지된다.
따라서 어떠한 경우에도 두 개의 return ... 명령문이 실행되지 않기에
함수의 반환값은 하나다.
하지만 그렇다고 해서 함수 본문에 return ... 명령문이 한 번만 사용된다는 의미는 아니다.
예를 들어, 아래 myAddProd() 함수는 두 인자의 크기를 비교한 결과에 따라
덧셈 또는 곱셈을 실행한 결과를 반환값으로 지정한다.
def myAddProd(left, right):
if left < right:
sum_ = left + right
return sum_
else:
prod_ = left * right
return prod_두 인자의 크기에 따라 덧셈 또는 곱셈의 결과가 반환되지만
하지만 어떤 경우에도 return sum_ 과 return prod_ 가 동시에 실행되지는 않는다.
이런 의미에서 함수의 반환값은 항상 하나다.
myAddProd(-2, 5)3myAddProd(5, -2)-10심지어 아래 useless() 함수처럼 return ... 명령문을 연속해서
작성하더라도 마찬가지다.
먼저 실행된 return sum_ 명령문에 의해 sum_에 할당된 값이 반환되면
바로 함수의 실행을 멈춘다.
즉, return prod_ 는 절대로 실행되지 않는다.
def useless(left, right):
sum_ = left + right
prod_ = left * right
return sum_
return prod_ # 절대 실행되지 않음useless(-2, 5)310.2.3None 반환값¶
아래 코드에 정의된 double_int() 함수의 정의는 return ... 명령문을 사용하지 않는다.
즉, 반환값을 지정하지 않는다.
def double_int(num_param):
double_param = num_param * 2return ... 명령문이 없는 함수를 호출하면 반환값이 지정되지 않는다.
예를 들어 double_int(5)를 실행해도 아무런 값이 표시되지 않는다.
double_int(5)아래 코드처럼 double_int(5)에 의해 계산된 값을 화면에 출력하려 하면
None 이라는 이상한 값이 출력된다.
print(double_int(5))None
앞서 설명한 대로 double_int(5)가 호출되면
아래 코드가 실행된다.
num_param = 5
double_param = num_param * 2따라서 double_param 변수에 10이 할당되는데 이후에 실행할 아무런 명령문도 없기에
반환값이 지정되지 않은 채로 함수의 실행이 종료된다.
파이썬 실행기는 이런 경우에 반환값을 None으로 강제 지정한다.
따라서 double_int() 함수는 실제로는
아래 코드처럼 정의된 것으로 간주된다.
def double_int(num_param):
double_param = num_param * 2
return None # None 반한값 지정None 값
None은 '아무런 의미가 없음’을 의미하는 값이다.
따라서 0, 비어있는 문자열, 비어 있는 리스트처럼 거짓으로 취급된다.
bool(None)False반면에 None도 하나의 값이라서 변수 할당에 사용되어 저장될 수 있다.
x = double_int(5)
print(x)None
하지만 예를 들어 연산 등에 활용하면 허용되지 않는 인자라는 이유로 TypeError 오류가 발생한다.
x + 1---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
Cell In[28], line 1
----> 1 x + 1
TypeError: unsupported operand type(s) for +: 'NoneType' and 'int'print() 함수의 반환값
반환값이 None인 대표적인 함수가 print() 함수이다.
그런데 print() 함수를 아래와 같이 활용하면 마치 인자를 그대로 반환하는 것처럼 보인다.
print(3.14)3.14
하지만 화면에 출력되는 문자열은 반환값이 아니다.
다만 print() 함수의 본문에 포함된 명령문 중에서
지정된 값을 화면에 출력하는 명령문이 실행된 결과에 불과하다.
앞서 설명한 대로 print(3.14)의 반환값은 None임을 아래 코드가 확인해준다.
먼저 print(3.14) 가 가리키는 값을 변수 x에 할당하자.
아래 코드를 실행했을 때 보여지는 3.14는 반환값이 아니라 지정된 인자가 화면에 출력된 결과이다.
x = print(3.14)3.14
x에 할당된 값을 확인하려 하면 아무 것도 보여지지 않는다.
xx에 할당된 None을 확인하려면 print() 함수를 이용해야 한다.
print(x)None
10.2.4람다 함수¶
특별한 목적으로 한 번만 사용되는 함수가 필요할 때, 그리고 함수의 본문이 매우 간단할 때 함수의 이름을 지정하지 않으면서 아래 형식으로 함수를 정의할 수 있다.
lambda 매개변수1, ..., 매개변수n : 표현식lambda(람다)는 그리스어 알파벳 λ(lambda)를 가리키며, 람다를 이용한다는 이유로 람다 함수라 부른다.
예를 들어 두 인자의 곱을 반환하는 람다 함수는 아래와 같이 정의된다.
a와b: 매개변수 2개콜론 기호
:뒤의 표현식a * b: 람다 함수의 반환값
lambda a, b : a * b<function __main__.<lambda>(a, b)>람다 함수는 자신을 가리키는 이름이 없기에 람다 함수를 호출하려면 항상 람다 함수 정의 자체를 사용해야 해서 조금 불편하다. 아래 코드는 2와 5의 곱을 계산하는 람다 함수 호출식이다.
(lambda a, b : a * b)(2, 5)10이렇듯 람다 함수는 함수 자체를 활용하기에는 많이 불편하지만 람다 함수 고유의 기능이 따로 있기에 여기서 간단하게 소개해 둔다.
10.3위치 인자와 키워드 인자¶
함수의 인자는 위치 인자와 키워드 인자 두 종류로 구분된다.
위치 인자positional argument: 반드시 순서에 맞게 지정해야 하는 인자
키워드 인자keyword argument: 필요에 따라 추가로 지정할 수 있는 인자
함수를 정의할 때
한 종류의 인자만 사용하도록 해도 되고 두 종류의 인자를 섞어서 사용하도록 해도 된다.
단, 두 종류의 인자를 모두 사용하도록 하려면
위치 인자를 먼저, 키워드 인자를 나중에 오도록 해야 한다.
print() 함수를 이용하여 위치 인자와 키워드 인자의 활용법을 소개한다.
10.3.1print() 함수의 인자¶
여러 개의 값을 화면에 출력하려면 print() 함수에 여러 개의 인자를 지정하여 호출한다.
그러면 인자들이 공백으로 구분되어 함께 한 줄에 출력된다.
예를 들어 아래 코드는 안녕, 파이썬, ! 세 개의 문자열을 공백으로 구분하면서 한 줄에 출력한다.
print('파이썬', '안녕', '!')파이썬 안녕 !
출력 대상으로 지정된 세 개의 인자가 공백으로 구분되어 한 줄에 출력되는 이유는
sep이라는 키워드 인자를 받는 매개변수 때문이다.
위 코드를 실행하면 파이썬 실행기는 실제로는 아래 코드를 실행한다.
print('파이썬', '안녕', '!', sep=' ')파이썬 안녕 !
변수 할당 명령문 형식처럼 생긴 sep=' '은 화면에 출력해야할 인자들을 공백으로 구분하여 한 줄에 출력하도록
하는 옵션 기능을 지정한다.
키워드 인자 변경
키워드 인자에 할당된 값은 임의로 바꿀 수 있다.
예를 들어, 출력 대상으로 지정된 각각의 인자를 하이픈 기호-로 구분하려면
즉, 인자와 인자를 하이픈으로 연결하려면
아래 코드에서처럼 sep 매개변수에 문자열 -을 키워드 인자로 지정하면 된다.
print('파이썬', '안녕', '!', sep='-')파이썬-안녕-!
위 코드에서 print() 함수를 호출할 때 사용된 위치 인자와 키워드 인자는 다음과 같다.
위치 인자: 화면 출력에 사용되는 세 개의 인자,
'파이썬','안녕','!'키워드 인자:
sep매개변수에 할당된 문자열'-'
print() 함수의 키워드 인자
print() 함수의 위치 인자는 0개 이상 원하는 만큼 사용할 수 있다.
반면에 키워드 인자는 sep 이외에 end, file, flush 매개변수에 할당될 수 있다.
실제로 print() 함수의 헤더는 다음과 같다.
print(value, ..., sep=' ', end='\n', file=sys.stdout, flush=False)매개변수 각각의 역할은 다음과 같다. 키워드 인자들은 특별한 기능을 수행하며, 그 기능을 그대로 사용하는 경우 함수 호출 과정에서 굳이 언급할 필요가 없다.
Table 1:print()함수의 키워드 인자
매개변수 | 기능 |
|---|---|
| 위치 인자. 출력에 사용할 값 하나를 인자로 받을 수 있음. |
말줄임표( | 여러 개의 위치 인자를 사용할 수 있음을 의미함. |
| 위치 인자들을 구분하는 문자열 지정. 기본 키워드 인자는 공백 문자. |
| 위치 인자를 모두 출력한 후에 출력하는 문자열 지정. 기본 키워드 인자는 줄바꿈 문자. |
| 화면 출력 방식 지정. 기본 키워드 인자는 화면 출력. |
| 플러쉬 기능 사용 여부 지정. 기본 키워드 인자는 |
예를 들어, end 매개변수의 기본 키워드 인자가 줄바꿈이기에 print() 함수를 호출한 다음엔 항상 줄바꿈이 실행된다.
만약에 빈 문자열 ''을 end 매개변수에 할당하면 줄바꿈을 하지 않는다.
아래 두 코드를 비교하면 end 매개변수의 역할을 확인할 수 있다.
기본 키워드 인자를 그대로 사용한 경우: 첫째
print()함수 호출에 의해'파이썬 안녕 !'이 출력된 후에 줄바꿈이 이뤄지고 그 다음에 둘째print()함수 호출에 의해'==='문자열이 출력됨.
print('파이썬', '안녕', '!')
print('===')파이썬 안녕 !
===
end매개변수의 인자를 빈 문자열로 지정한 경우: 첫째print()함수 호출에 의해'파이썬 안녕 !'이 출력된 후에 줄바꿈을 하지 않은 채로 둘째print()함수 호출에 의해'==='문자열이 출력됨.
print('파이썬', '안녕', '!', end='')
print('===')파이썬 안녕 !===
print() 함수의 file과 flush 두 매개변수는 특별한 경우에 활용되며 여기서는 다루지 않는다.
두 매개변수의 간단한 예제는 print() 함수의 키워드 인자 기능에서 확인할 수 있다.
10.3.2키워드 인자 사용 함수 정의¶
아래 코드는 myAdd10() 함수를 키워드 인자를 이용하여
정의하는 방식을 보여준다.
사용된 두 매개변수의 역할은 다음과 같다.
left: 덧셈의 왼쪽 인자로 사용될 값을 할당받을 매개변수right: 덧셈의 오른쪽 인자로 사용될 값을 할당받을 매개변수. 10이 기본 키워드 인자로 지정됨.
def myAdd10(left, right=10):
return left + right아래 코드에서처럼 myAdd10() 함수를 호출할 때 둘째 인자가 생략되면 자동으로 10이 대신 사용되어
인자가 주어지면 10을 더한 값이 반환되는 함수처럼 사용된다.
myAdd10(5)15실제로는 아래 코드와 동일하게 작동한다.
myAdd10(5, 10)1510이 아닌 다른 값을 right 매개변수의 키워드 인자로 지정하려면
아래 코드와 같이 함수 호출을 실행한다.
myAdd10(5, right=20)2510.4지역 변수와 전역 변수¶
10.4.1매개 변수와 지역 변수¶
아래 square_return() 함수는 하나의 인자와 함께 호출되면 인자의 제곱을 반환한다.
seventeen = 17
def square_return(number):
square = number ** 2
return squaresquare_return() 함수의 매개변수 number와 함수 본문에서 정의된 squre 두 변수는
square_return() 함수와 독립적으로 사용될 수 없다.
이는 함수가 호출되어 실행이 완료된 이후에도 마찬가지다.
이유는 함수가 실행되는 과정에서 선언된 변수들은
모두 함수의 실행이 종료되는 순간 컴퓨터 메모리에서 삭제되어 더 이상 사용될 수 없기 때문이다.
예를 들어 아래 함수 호출을 실행하자.
square_return(seventeen)289number와 square 변수를 확인하려 하면 NameError 오류가 발생한다.
number---------------------------------------------------------------------------
NameError Traceback (most recent call last)
Cell In[46], line 1
----> 1 number
NameError: name 'number' is not definedsquare---------------------------------------------------------------------------
NameError Traceback (most recent call last)
Cell In[47], line 1
----> 1 square
NameError: name 'square' is not defined즉, number와 square 두 변수가 존재하지 않는다.
반면에 seventeen 변수는 언제나 사용할 수 있다.
print("seventeen 변수:", seventeen)seventeen 변수: 17
number와 square 변수처럼 함수를 선언할 때 사용되는 매개변수와 함수 본문에서 선언되는 변수는
함수가 실행되는 동안에만 의미를 갖는다는 의미에서 지역 변수local variable라 한다.
반면에 seventeen 변수처럼 함수 밖에서도 의미를 갖는 변수는 전역 변수global variable라 부른다.
함수 호출 과정에서 계산된 값들 중에 일부를 함수 호출이 끝난 후에도 활용하려면 반환값으로 지정해야 한다. 예를 들어 17의 제곱을 계산해서 활용하고자 한다면 다음과 같이 반환값을 변수에 할당해서 활용한다.
square17 = square_return(seventeen)
print("17의 제곱:", square17)17의 제곱: 289
지역 변수와 전역 변수의 이름은 구분해서 작성하는 게 좋다.
그렇지 않으면 아래 코드가 보여주듯이 혼란스러워질 수 있다.
아래 코드에서 square 가 전역 변수와 지역 변수로 사용된다.
하지만 두 변수는 서로 상관이 없다.
seventeen = 17
square = 2
def square_return(number):
square = number ** 2
return square아래 코드에서 마지막에 호출되는 print(squre) 는 전역 변수 square에 할당된 2를 출력한다.
이유는 square_return() 함수의 본문에 사용된 지역 변수 square는 함수가 호출되어 실행되는 과정에서만
존재하고 함수의 실행이 종료되는 순간 컴퓨터 메모리에서 삭제되기 때문이다.
print(square)2
반면에 square_return() 함수의 본문에서 사용되는 squre 변수는 지역 변수를 가리킨다.
예를 들어 아래 코드에서 return square 명령문의 square는 인자 10의 제곱인 100을 가리키며,
따라서 100이 함수의 반환값으로 지정되었다.
print('10의 제곱:', square_return(10))10의 제곱: 100
10.4.2global 키워드¶
전역 변수는 함수 내에서의 활용이 제한된다. 아래 코드는 전역 변수를 함수 내에서 활용할 수 있음을 보여준다.
# 전역 변수
a = 15
def add_a(b):
c = a + b # 전역 변수 a 활용
return c
print(add_a(10))25
하지만 함수 내에서 전역 변수 재할당을 시도하면 오류가 발생한다.
# 전역 변수
a = 15
def add_a(b):
c = a + b # 지역 변수 a 활용 시도.
a = 50 # 지역 변수 a 선언. 너무 늦게 선언됨.
return c
print(add_a(10))---------------------------------------------------------------------------
UnboundLocalError Traceback (most recent call last)
Cell In[54], line 9
6 a = 50 # 지역 변수 a 선언. 너무 늦게 선언됨.
7 return c
----> 9 print(add_a(10))
Cell In[54], line 5, in add_a(b)
4 def add_a(b):
----> 5 c = a + b # 지역 변수 a 활용 시도.
6 a = 50 # 지역 변수 a 선언. 너무 늦게 선언됨.
7 return c
UnboundLocalError: cannot access local variable 'a' where it is not associated with a value이유는 함수 본문에서 변수 할당 명령문이 포함되면 파이썬 실행기가 해당 변수를
지역 변수로 처리하기 때문인데,
위 코드의 6번 줄에 있는 변수 할당문으로 인해 변수 a가 지역 변수가 된다.
그런데 5번 줄에서 아직 선언되지 않은 지역 변수 a를 사용하려 하기에
UnboundLocalError 라는 오류가 발생한다.
반면에 아래 코드는 오류 없이 실행된다.
이유는 지역 변수 a가 먼저 선언된 후에 활용되기 때문이다.
# 전역 변수
a = 15
def add_a(b):
a = 50 # 지역 변수 a 선언
c = a + b # 지역 변수 a 활용
return c
print(add_a(10))60
전역 변수를 함수 내에서 제한 없이 활용하려면
함수 본문에서 global 키워드를 이용하여 해당 변수를 지정해야 한다.
예를 들어 아래 코드는 전역 변수 a를 함수 내부에 활용뿐만 아니라 재할당까지 할 수 있음을 보여준다.
# 전역 변수
a = 15
print('전역 변수 a가 원래 가리키는 값:', a)
def add_a(b):
global a
c = a + b # 전역 변수 a 활용
a = 50 # 전역 변수 a 재할당
return c
print("함수 호출 결과:", add_a(10))
print('전역 변수 a가 가리키는 다른 값:', a)전역 변수 a가 원래 가리키는 값: 15
함수 호출 결과: 25
전역 변수 a가 가리키는 다른 값: 50
10.5순수 대 비순수¶
아래 add_impure() 함수는 전역 변수 a의 값을
함수가 실행할 때마다 업데이트 한다.
반면에 fun_a() 함수는 전역 변수 a를 활용만 한다.
a = 15
def add_impure(b):
global a
c = a + b
a = c # 전역 변수 a 업데이트
return c
def fun_a(x):
return x + aadd_impure() 함수는 호출될 때마다 전역 변수 a의 업데이트 한다.
따라서 동일 인자에 대해서도 다른 값을 반환한다.
add_impure(10)25add_impure(10)35fun_a() 함수는 전역 변수 a를 활용하기에 add_impure() 함수에 영향을
간점적으로 받는다.
예를 들어 그냥 두 번 호출하면 동일 인자에 대해 동일한 값을 반환한다.
fun_a(1)36fun_a(1)36그런데 add_impure() 함수가 호출되면 fun_a() 함수의 반환값이 동일 인자에 대해서 달라진다.
add_impure(10)
fun_a(1)46반환값을 생성하는 것 이외에 전역 변수등을 변경하여 메모리의 상태를 변화시키는 기능을 함수의 부작용side effect이라 하며, 부작용을 갖는 함수를 비순수 함수impure function라 부른다. 반면에 반환값을 계산할 때 함수의 매개 변수와 함수 본문에서 선언된 지역 변수만을 활용하여 함수 외부로부터 영향을 받거나 영향을 주는 부작용이 없는 함수는 순수 함수pure function라 부른다.
프로그래밍에 비순수 함수가 반드시 필요하지는 않지만
편리성과 효율성 때문에 활용되곤 한다.
하지만 앞서 보았듯이 비순수 함수를 사용하다 보면 전역 변수의 값 등 메모리의 상태가 달라져서
fun_a()와 같은 함수에 의도치 않은 영향을 줄 수 있는 가능성이 매우 높다.