상세 컨텐츠

본문 제목

[ Python 기초 문법 ] - 프로그램 입출력(1) - 함수

Language/Python

by bing_su 2023. 8. 14. 10:15

본문

반응형
SMALL

함수를 설명하기 전에, 믹서로 과일 주스를 만드는 과정을 살펴보자. 주스를 만들기 전, 우리는 믹서에 과일을 넣는다. 그리고 믹서를 사용하여 과일을 갈아 과일 주스를 만든다. 우리가 믹서에 넣는 과일이 '입력', 과일 주스가 '출력(결괏값)'이 되는 것이다. 이때 믹서는 과일을 입력받아 주스를 출력하는 '함수'가 된다.

함수를 주스 만드는 과정에 비유

프로그래밍에서 함수는 어떠한 특정한 일을 수행하는 독립적인 단위를 뜻한다. 즉, 입력값(Input)을 가지고 어떠한 작업을 수행한 후 출력값(Output)을 내어 놓는 역할을 한다. 프로그래밍에서 이러한 함수는 굉장히 중요한 역할을 한다. 그러니 정말 본격적으로 공부해 봅시다!

[ 함수를 사용하는 이유 ]

프로그래밍을 하다 보면 반복적으로 작성되고 사용되는 부분이 있다. 이때 반복적으로 사용되는 부분을 한 뭉치로 묶어서 '어떤 입력값을 주었을 때 어떠한 결괏값을 돌려준다'는 함수로 사용할 수 있다.
또한, 본인이 만든 프로그램을 함수화하면 프로그램 흐름을 파악하기 쉽다. 따라서 프로그램에서 오류가 날 때도 파악하기가 쉬워진다. 결국엔 함수를 잘 사용하고 적절하게 만들 줄 아는 것이 중요하다는 것이다.

[ 파이썬 함수의 기본 구조 ]

파이썬에서 사용하는 함수의 기본 구조를 살펴보면 아래와 같다.

def Function_Name(parameter):
    Sentence 1
    Sentence 2
    …

먼저, def는 함수를 만들 때 사용하는 예약어다. 함수명은 프로그래머가 임의로 만들면 된다. 함수 이름 뒤의 매개변수(parameter)는 함수에 입력될 값이라는 뜻이다. 콜론(:)을 이용하여 함수 블록을 정의하고 앞서 봐 온 조건문, 반복문처럼 수행할 문장을 입력하면 된다. 아래[ 입의 예시를 통해 함수에 대해 쉽게 이해할 수 있다.

>>> def add(a, b):  # a, b를 parameter로 가지는 함수 add 정의
…    return a+b  # 함수의 결괏값을 a+b로 반환
…
>>> a = 3  # argument a는 3
>>> b = 4  # argument b는 4
>>> c = add(a, b)  # add(3, 4)의 반환값을 c에 대입
>>> print(c)  # c 값 출력
7

간단히 설명하면, 우리가 정의한 함수의 이름은 add고, parameter로 a와 b 2개의 입력값을 받는다. 그리고 결괏값으로 2개의 입력값을 더한 값을 반환한다.

※ 매개변수(parameter)와 인수(arguments)

위의 코드를 참고하며 설명을 읽자. 매개변수(parameter)는 함수에 입력으로 전달되는 값을 받는 변수다. 인수(arguments)는 함수를 호출할 때 우리가 전달하는 입력값 자체를 의미한다.

[ 입력값과 결괏값에 따른 함수의 형태 ]

함수는 입력값을 받아 어떠한 처리를 하여 적절한 결괏값을 출력한다. 함수의 형태는 입력값과 결괏값의 존재 유무에 따라 4가지 유형으로 나뉜다. 이제부터 하나씩 살펴보자.

1. 일반적인 함수: 입력값이 있고, 결괏값이 있는 함수

Returned_Variable = Function_Name(parameter_1, parameter_2, …)

입력값이 있고 그에 따른 결괏값이 있는 전형적인 함수 형태다. 앞으로 많이 사용하게 될 형태다. 아래의 예시 코드를 보며 더 자세히 이해해 보도록 하자.

>>> def add(a, b):  # a, b를 parameter로 가지는 함수 add 정의
…    result = a + b  # a + b의 값을 result 변수에 저장
…    return result  # result 값을 반환
…
>>> a = add(3, 4)
>>> print(a)
7

 

2. 입력값이 없는 함수: 입력값이 없고, 결괏값만 있는 함수

Returned_Variable = Function_Name()

입력값이 없는 함수, 즉, parameter가 없는 함수도 존재한다. 아래의 예시 코드로 해당 함수의 사용 방법을 이해해보자. 

>>> def say():  # parameter가 존재하지 않는 함수 say 정의
…    return "Hi"  # 문자열 "Hi"를 반환
…
>>> a = say()
>>> print(a)
Hi

3. 결괏값이 없는 함수: return 명령어(결괏값)이 없는 함수

Function_Name(parameter_1, parameter_2, …)

결괏값이 없는 함수는 호출해도 돌려주는 값이 없다. 아래의 예시 코드로 해당 함수를 이해해 보자.

>>> def add(a, b):  # a, b를 parameter로 가지는 함수 add 정의
…    print("{0} plus {1} is {2}.".format(a, b, a+b))  # 반환값 X. print 함수만 실행하는 함수.
…
>>> add(3, 4)  # return 값이 없어서 함수명을 직접 입력하여 호출해야 함
3 plus 4 is 7.
>>> a = add(3, 4)
3 plus 4 is 7  # 함수가 실행된 결과 출력
>>> print(a)
None  # 반환된(return 된) a 값 자체가 없기 때문에 None 출력

함수에서 결괏값은 오직 return 명령어로만 돌려받을 수 있음을 기억하자. print문과 같은 문장은 함수의 구성 요소 중 <수행할 문장>에 해당하는 부분일 뿐이다.

4. 입력값 결괏값 둘 다 없는 함수: 입력값과 return 명령어(결괏값)가 모두 없는 함수

Function_Name()

입력을 받는 parameter도 없고 결괏값을 반환하는 return문도 없는 함수다. 예시 코드를 통해 이해해 보자.

>>> def say():  # parameter이 없는 함수
…    print("Hi")  # 반환값 X. print 함수만 실행함.
…
>>> say()
Hi

[ 매개변수를 지정하여 호출 ]

함수를 호출할 때 매개변수를 지정할 수도 있다. 아래의 예시를 통해 이해해 보자.

>>> def add(a, b):  # a, b parameter로 가지는 함수 add 정의
…    return a + b  # a+b 값을 반환값
…
>>> result = add(a=3, b=7)  # a에 3, b에 7을 직접 전달.
>>> print(result)
10

>>> result = add(b=5, a=3)  # b에 5, a에 3을 직접 전달.
>>> print(result)
8

[ 입력값이 몇 개가 될지 모를 때 ]

입력값의 개수가 무조건 정해지지 않을 경우도 있다. 이러한 문제를 해결하기 위해서 아래와 같은 방법으로 해결할 수 있다. 일반적으로 볼 수 있는 함수 형태에서 괄호 안의 parameter 부분이 *parameter로 바뀌었다.

def Function_Name(*parameter):
    Sentence 1
    …

아래의 예시 코드를 보며 입력값이 정해지지 않았을 경우에 대해 생각해 보자.

def add_many(*args):  # parameter가 몇 개인지 몰라서 *args 형태로 지정
    result = 0
    for i in args:  # 변수 i에 parameter를 차례로 대입하며 동작함.
        result = result + i  # args에서 입력 받은 모든 값을 더함.
    return result  # args 값의 총합을 반환.

result = add_many(1, 2, 3)  # argument로 1, 2, 3을 지정.
print(result)

# 출력 화면
6

*args처럼 parameter 이름 앞에 *을 붙이면 입력값을 전부 모아서 튜플로 만들어준다. 위의 코드에서는 add_many(1, 2, 3)로 함수를 사용하므로, args는 (1, 2, 3)이 되는 것이다. 예시로 사용한 *args는 arguments의 약자며 관례적으로 자주 사용하는 변수명이다. 사용자에 따라 변수명은 *python, *a 등과 같이 다르게 사용해도 된다.
 
여러 개의 입력을 처리할 때, def add_many(*args)와 같이 매개변수로 *args 하나만 사용할 수 있는 것은 아니다. 이게 무슨 의미인지 아래의 예시 코드를 살펴보며 이해해 보자.

'''
하나의 값을 입력 받을 수 있는 choice와 
여러 개의 값을 입력 받을 수 있는 *args를 parameter로 지정
'''
def calculate(choice, *args):
    if choice == "add":  # parameter choice에 'add'를 입력 받았을 때
        result = 0
        for i in args:  # 변수 i에 args 값을 차례로 대입하며 동작함.
            result = result + i  # args에서 입력 받은 모든 값을 더함.
    elif choice == "mul":  # parameter choice에 'mul'을 입력 받았을 때
        result = 1
        for i in args:  # 변수 i에 args 값을 차례로 대입하며 동작함.
            result = result * i  # args에서 입력 받은 모든 값을 곱함.
    return result  # 연산 결괏값 반환

# choice에는 argument로 'add' 지정, *args는 1, 2, 3, 4, 5 지정
result1 = calculate('add', 1, 2, 3, 4, 5)
print(result1)
result2 = calculate('mul', 1, 2, 3, 4, 5)
print(result2)

# 출력 화면
15
120

calculate 함수에서 choice 매개변수 값에 따라 반환값(연산 결과)이 달라질 수 있다.

[ 함수의 결괏값은 언제나 하나다. ]

def calculation(a, b):  # a, b를 parameter로 가지는 함수 calculation 정의
    return a+b, a*b  # 반환 값이 a+b, a*b로 두 종류
result = calculation(3, 4)  # argument 3, 4를 calculation 함수에 전달
print(result)

# 출력 화면
(7, 12)  # 튜플 값 하나로 함숫값이 반환됨.

함수의 반환 값이 a+b, a*b와 같이 한 종류가 아닌 여러 종류일 때는 튜플로 함숫값이 반환된다. (오류가 발생하지 않는다는 것!) 즉, 위의 예시 코드에서 result 변수는 (7, 12)라는 튜플값을 가지게 되는 것이다.
 
그리고 함수는 return 문을 만나는 순간 결괏값을 반환한 후 함수에서 빠져나간다. 따라서 아래의 예시 코드 두 종류는 완전히 같은 것이 된다. return문에 대해 주의하며 함수를 사용하자.

''' program #1 '''
def calculation(a, b):
    return a + b
    return a * b  # return a + b가 실행되어 실행되지 않는 구문이 되어버림.
result = calculation(2, 3)
print(result)

# 출력 화면
5

''' program #2 '''
def caculation(a, b):
    return a + b
result = calculation(2, 3)
print(result)

# 출력 화면
5

특정 상황에서 함수를 빠져나가기 위해 return을 단독으로 쓸 수도 있다. (반복문에서 배운 break랑 비슷한 기능을 한다고 생각하시면 됨.) 이 방법은 실제 프로그래밍을 할 때도 자주 사용되니 기억해 두자.

def say_nick(nick):  # nick을 parameter로 가지는 함수 say_nick 정의
    if nick == "stupid":  # nick 변수값이 문자열 "stupid"일 때 동작
        return  # 아래의 print문을 실행하지 않고 그대로 함수 실행 종료.
    print("My nick name is {0}.".format(nick))  # 닉네임을 출력하는 print문
say_nick("genius")

#출력 화면
My nick name is genius.

say_nick("stupid")  # argument로 "stupid" 전달 -> print문 실행 안 되고 즉시 함수 종료.

# 출력 화면

[ 매개변수에 초기 값 미리 설정 ]

매개변수에 아래와 같이 초기 값을 미리 설정하여 사용할 수 있다. 함수에서 쓰이는 매개변수가 변하지 않는 값일 경우에는 아래와 같이 초기 값을 설정하는 것이 유용하다.

# 이제 주석 많이 안 달고 필요한 내용만 설명함. 알아서 따라오세요.
def say_myself(name, old, man=True):  # parameter 중 man에는 True 값을 미리 설정함.
    print("My name is {0}.".format(name))
    print("I am {0} years old.".format(old))
    if man:
        print("I am a man.")
    else:
        print("I am a woman.")

아래와 같이 전달하는 argument에 따라 결과가 출력된다. 이런 방법으로 함수를 사용할 때는 초기 값을 설정한 parameter의 위치를 주의해야 한다. 초기 값을 적용하기 위한 parameter들은 항상 뒤쪽에 위치해야 한다.

# 초기 값이 True인 경우
say_myself("Henry", 33)  # man 변수에 입력값이 없으면 초기 값인 True를 갖게 됨.
say_myself("Henry", 33, True)  # man 변수에 True 값 지정.

# 출력 화면
My name is Henry.
I am 33 years old.
I am a man.

# 초기 값이 False인 경우
say_myself("sooob", 24, False)  # man 변수에 출력값이 없으면 초기 값인 False를 갖게 됨.

# 초기 값이 False인 경우의 출력값
My name is sooob.
I am 24 years old.
I am a woman.

[ 함수 안에서 선언된 변수의 효력 범위 ]

아래와 같이 함수 밖에서 1의 값을 가지는 변수 a를 선언하고, 반환 값을 돌려주지 않는 vartest 함수를 선언하자. 그리고 vartest 함수에 입력값 a를 주고, a를 출력해 보자.

a = 1  # 함수 바깥에 변수 a 선언.
def vartest_a(a):  # a를 parameter로 가지는 vartest_a 함수 선언.
	a = a + 1
vartest_a(a)  # argument로 a 전달.
print(a)  # a 값 출력

# 출력 화면
1

함수에서 변수에 1을 더해서 2가 출력이 될 것 같지만, 결괏값은 1이 나온다. 함수 내부에 있는 a는 함수 안에서만 사용되는 '함수만의 변수'이기 때문이다. 즉, vartest 함수에서 parameter로 쓰이는 변수 a는 함수 밖에서 선언된 변수 a와는 다른 것이다. 즉, 아래의 코드는 실행하면 오류가 발생한다.

def vartest(a):
    a = a + 1

vartest(3)  # argument로 3을 전달
print(a)  # a 값 출력 -> 정의된 변수 a가 없어서 NameError 뜸.

여기서 NameError는 파이썬에서 발생하는 에러의 한 종류로, 변수와 관련해서 많이 발생한다. 해당 프로그램에서 NameError가 뜨는 이유는 변수가 선언되지 않았는데 출력하려고 했기 때문이다. 즉, 함수 안에서만 사용되는 parameter a를 함수 밖에서 출력하려고 했기 때문에 해당 오류가 발생한다는 것이다. 이를 잘 이해하고 넘어가자.

[ 함수 안에서 함수 밖의 변수를 변경 ]

위의 예시에서 살펴본 vartest 함수를 사용해서 함수 외부에 있는 변수 a를 1만큼 증가시킬 수 있는 방법은 return을 이용하는 방법과 global 명령어를 이용하는 방법이 있다. 아래에서 조금 더 자세히 살펴보자.

1. return 사용

a = 1  # 함수 바깥에 변수 a 선언
def vartest(a):  # a를 parameter로 가지는 vartest 함수 선언
    a = a + 1
    return a  # a를 연산한 값이 반환되는 함수. (결괏값 O)
# argument로 함수 바깥에서 선언된 a 전달 -> vartest 함수 실행 결괏값을 변수 a에 갱신(다시 저장.)
a = vartest(a)  
print(a)  # a의 최종 값 출력

# 출력 화면
2

vartest 함수는 argument로 전달받은 값에 1을 더한 값을 반환하는 함수다. 즉, a = vartest(a)를 수행하면, a 변수에는 vartest 함수에서 반환된 결괏값이 대입되는 것이다. 물론 함수 내부에 존재하는 parameter a는 함수 내부에서만 쓰이고, 함수 밖에서 쓰이는 변수 a와는 다른 것이다.

2. global 명령어 사용

a = 1  # 함수 바깥에 변수 a 선언
def vartest():  # parameter를 가지지 않는(=입력값이 없는) 함수 vartest 선언
    global a  # global 명령어로 함수 밖의 변수 a를 사용. (아래에서 설명할 것.)
    a = a + 1
vartest()
print(a)  # a 값 출력.

# 출력 화면
2

vartest 함수 내부에 있는 global a는 함수 내부에서 함수 밖의 변수 a를 직접 사용하겠다는 의미를 가진다. 그런데 이 방법은 결론부터 말하면 별로 사용하지 않는 것이 좋다. 왜냐하면 함수는 독립적으로 존재하는 것이 가장 좋기 때문이다. 외부 변수에 종속하는 함수는 그다지 좋은 함수가 아니라는 것이다. 따라서 global 명령어를 사용하기보다 첫 번째 방법인, 함숫값을 반환하는 방법을 사용하기를 권장한다.

[ lambda 예약어 ]

lambda 역시 함수를 생성할 때 사용하는 예약어로 def와 동일한 역할을 한다. 보통 함수를 한 줄로 간결하게 만들 때나 def를 사용할 수 없을 때 주로 쓰인다. 해당 예약어를 쓰는 기본적인 방법을 정리하면 아래와 같다.

lambda parameter_1, parameter_2, … : (Expression with parameters)

아래의 예시 코드를 보며 lambda의 사용법에 대해 이해하자. def를 사용한 함수와 기능이 완전히 동일함을 확인할 수 있다.

''' program #1 - lambda 사용 '''
add = lambda a, b: a+b  # a, b를 parameter로 받아 a+b 연산을 수행하는 함수 add 선언.
result = add(3, 4)  # argument로 3, 4 전달하여 add 함수 실행
print(result)  # result 값 출력

# 출력 화면
7

''' program #2 - def 사용 '''
def add(a, b):
    return a+b
result = add(3, 4)
print(result)

# 출력 화면
7

 

반응형
LIST

관련글 더보기

댓글 영역