파이썬 함수를 작성하는 방법

파이썬 함수를 작성하는 방법

반복적인 코드는 좋지 않다는 것을 누구나 알고있다. 보기에도 좋지 않고 복사한 코드 한 부분에 고쳐야 할 부분이 있다면 복사했던 부분을 다시 다 고쳐야하기 때문이기도 하다. 이번에는 함수를 작성하는 법과 함수를 사용해서 코드의 반복을 줄이는 법을 배워보려고 한다.


파이썬 함수 해부하기

모든 함수는 다음과 같이 두 가지 부분으로 나뉘어져 있다.
  1. 함수 시그니처(서명)은 함수의 이름과 예상되는 인풋을 정의한다.
  2. 함수 바디(본문)은 함수가 사용할 때 마다 실행되는 코드를 포함한다.

다음이 함수의 시그니처(signature), 바디(body), 리턴문(return statement)의 기본적인 생김새이다.

def multiply(x, y): # 함수 시그니처
	# 함수 본문
	product = x * y
	return product

함수 시그니처(Function Signature)

함수 안에 코드의 첫 줄을 함수 시그니처(function signature)라고 부른다. 함수 시그니처는 항상 def 키워드로 시작하는데, def"정의하다(define)"라는 의미이다.

위에서 사용했던 multiply 함수를 더욱 자세히 들여다보자.

def multiply(x, y):
함수 시그니처는 총 네 가지 파트로 구성되어 있다.
  1. def 키워드
  2. 함수 이름(multiply)
  3. 매개 변수 리스트(x, y)
  4. 콜론(:)

파이썬은 def 키워드로 시작하는 행을 읽으면 새로운 함수를 생성한다. 함수는 함수 이름과 동일한 이름의 변수에 할당된다.

함수 이름이 곧 변수 이름이므로, 함수의 이름은 변수의 이름과 같은 법칙을 따라야한다. 즉, 함수 이름은 오직 숫자, 문자, 밑줄만 가질 수 있으며, 절대 숫자로 시작해서는 안된다.

매개변수 리스트는 괄호로 둘러싸인 매개변수 이름들의 리스트이다. 매개변수 리스트는 함수의 예상되는 인풋을 정의한다. 예제에서는 (x, y)multiply 함수를 위한 매개변수 리스트이다. 위 매개변수 리스트는 xy라는 매개변수를 생성한다.

매개변수는 값이 없는 점을 제외하고는 변수와 비슷하다. 매개변수는 함수가 하나 이상의 인수로 호출될 때 마다 제공되는 실제 값을 위한 자리 표시자 같은 역할이다.

함수 본문 안의 코드는 실제 값을 가진 변수인 것처럼 매개변수를 사용할 수 있다. 예를 들어, 함수 본문에 x * y와 같은 표현식이 포함될 수도 있는 것처럼 말이다.

xy가 아무 값이 없으므로, x * y도 아무 값을 가지지 않는다. 파이썬은 표현식을 템플릿과 같이 저장하고, 함수가 실행될 때 없는 값을 채운다. 함수는 매개변수를 가지지 않을 수도, 원하는 만큼 가질 수도 있다.


함수 본문(Function Body)

함수 본문(function body)프로그램 안에서 함수가 사용될 때 작동되는 코드이다. 함수 multiply의 본문은 다음과 같다.

def multiply(x, y):
	# 함수 본문
	product = x * y
	return product

보이는 것과 같이 함수 multiply는 단 두 줄의 코드를 가진 단순한 함수이다. 코드 첫 줄은 product라는 이름의 변수를 생성하고 값 x * y변수에 할당한다. 아직 x와 y는 값이 없으므로, 첫 줄은 실제로 함수가 실행될 때 변수 product할당되는 값을 위한 템플릿이다.

코드의 두 번째 줄은 리턴문(return statement)라고 불린다. 리턴문은 return 키워드로 시작되고, 변수 product가 뒤따른다. 파이썬은 리턴문에 닿는 순간 함수의 작동을 멈추고 product값을 반환한다.

한 가지 주목해야 할 점은 함수 본문안에 두 줄 다 들여쓰기가 적용되었다는 점이다. 파이썬 함수 작성시 매우 중요한 부분 중 하나이다. 함수 작성 시 함수 시그니처 아래 모든 줄은 예제와 같이 들여쓰기가 적용 되어야한다.

예를 들어, 다음의 print() 함수는 들여쓰기가 적용되지 않았기 때문에 함수 본문 안에 속하지 않는다.

def multiply(x, y):
	product = x * y
	return product

print("Where am I?") # 함수 본문 안에 포함 안됨.

만약 다음과 같이 print() 함수에 들여쓰기를 적용 했다면, 이전 줄이 비어있어도 함수 본문 안에 포함이 된다.

def multiply(x, y):
	product = x * y
	return product

	print("Where am I?") # 함수 본문 안에 있음.

한 가지 더 조심해야 할 부분은, 모든 줄의 들여쓰기는 통일되어야 한다는 점이다. 다음과 같이 들여쓰기가 더 많거나 적게 들여쓰기 되었다면 파이썬은 "unexpected indent"라는 에러를 발생시킨다.

def multiply(x, y):
	product = x * y
	 return product # 한 칸 더 들여쓰기가 되었음.
     
def multiply(x, y):
	product = x * y
   return product # 한 칸 덜 들여쓰기가 되었음.
파이썬에서 정해진 들여쓰기 수는 없다.
하지만 PEP 8에서는 네 칸의 들여쓰기를 하기를 권면한다.

파이썬에서 리턴문을 실행하면, 함수는 작동을 멈추고 값을 반환한다. 만약 리턴문 아래 들여쓰기가 잘 되어 함수 본문안에 속한 코드가 있더라도, 리턴문이 실행되면 그 어느 것도 실행되지 않는다.

다음과 같은 함수 안에서 print() 함수는 리턴문 아래 위치하므로, 함수 본문 안에 속해있어도 절대 실행되지 않는다. 즉 multiply() 함수가 호출되어도, "You can't see me!"라는 문자열은 절대 표시되지 않는다.

def multiply(x, y):
	product = x * y
	return product
	print("You can't see me!")

정의한 함수 호출하기

파이썬에서는 직접 정의한 함수를 호출하는 것도 가능하다.

multiply(2, 4)

내장 함수와는 다르게, 직접 정의한 함수는 def 키워드와 정의되지 않는 한 사용할 수 없다. 함수를 호출하기 전 반드시 함수를 정의해야 한다.

# 잘못된 예
num = multiply(2, 4)
print(num)

def multiply(x, y):
	product = x * y
	return product
        
Traceback (most recent call last):
  File "C:Usersdaveamultiply.py", line 1, in <module>
	num = multiply(2, 4)
NameError: name 'multiply' is not defined
        
# 올바른 예
def multiply(x, y):
	product = x * y
	return product

num = multiply(2, 4)
print(num)

리턴문이 없는 함수

파이썬에서 모든 함수는 값을 반환한다. 값이 None이어도 말이다. 하지만, 모든 함수가 리턴문이 필요한 것은 아니다. 예를 들어, 다음과 같은 함수도 파이썬에서는 유효한 함수이다.

def greet(name):
	print(f"Hello, {name}!")

greet() 함수는 리턴문이 없지만 완벽히 작동한다.

>>> greet("Dave")
Hello, Dave!

심지어 greet() 함수에 리턴문이 없어도 함수는 값을 가진다.

>>> return_value = greet("Dave")
Hello, Dave!
>>> print(return_value)
None

함수 문서화 하기

함수의 도움말을 보기위해서 파이썬의 help() 함수를 사용할 수 있다.

>>> help(len)
Help on built-in function len in module builtins:

len(obj, /)
	Return the number of items in a container.

help() 함수에 변수의 이름이나 함수의 이름을 전달하면, help() 함수는 전달받은 이름에 대해서 유용한 정보를 표시한다. 위와 같은 경우에는, help() 함수가 len이 컨테이너 안 아이템의 수를 반환하는 내장 함수라고 명시한다.

컨테이너란 다른 객체 들을 담고있는 객체를 위한 특별한 이름이다.
예를 들어, 문자열은 문자를 담고있는 컨테이너이다.

help() 함수를 multiply() 함수와 호출해보자.

>>> help(multiply)
Help on function multiply in module __main__:

multiply(x, y)

help() 함수가 함수 시그니처를 표시해주기는 하지만, 함수가 무엇을 하는지에 대해서는 아무 정보가 없는 것을 볼 수 있다. multiply() 함수에 대해서 더 잘 기록하기 위해서는 독스트링을 사용해야한다.

독스트링(docstring)이란 함수 본문 상단에 위치한 세따옴표로 이루어진 문자열 리터럴이다. 독스트링은 함수가 어떤 일을 하고 어떤 종류의 매개변수를 받는지 기록하는데 사용된다.

multiply() 함수에 독스트링을 다음과 같이 추가할 수 있다.

def multiply(x, y):
	"""Return the product of two numbers x and y."""
	product = x * y
	return product

독스트링을 작성하고 help() 함수를 multiply()함수와 호출 했을 때 다음과 같이 독스트링이 노출되는 것을 확인할 수 있다.

>>> help(multiply)
Help on function multiply in module __main__:

multiply(x, y)
	Return the product of two numbers x and y.
PEP 8에 독스트링에 대한 자세한 설명은 나와있지 않지만, 모든 함수에 하나의 독스트링을 갖도록 권면한다.

Reference