파이썬 기초

[파이썬 기초] 2. 파이썬 함수

빈이름 2024. 6. 11. 15:51
1. 파이썬 함수
    1.1. 함수의 역할
    1.2. 함수의 이름과 입력 인자
    1.3. 함수 내부와 외부 구분
    1.4. 함수의 출력
2. 함수가 갖는 변수
    2.1. 함수 내부의 변수
    2.2. 함수 외부의 변수
    2.3. 서로 다른 함수간의 관계

1. 파이썬 함수

1.1. 함수의 역할

파이썬 코딩을 위해서 변수와 함께 또 알아야 할 것은 함수입니다.

여러분이 알고 있는 함수는 어떤 뜻인가요? 함수 하면 아래와 같은 형태가 떠오르죠?

$$ f(x) = 3x + 5 $$

위 함수는 변수 x가 입력되었을 때, $3x+5$ 값을 결과로 출력하는 함수입니다. 코딩에서 함수도 이와 같은 역할을 합니다. 파이썬의 함수는 입력값이 들어오면, 그 값을 어떻게 어떻게 처리해서 결과값을 출력합니다.

그렇다면 함수는 언제 쓸까요? 함수는 반복되는 코드를 줄이기 위해서 사용됩니다.

코드를 작성하다 보면 반복적으로 필요한 기능이 존재할 때가 있습니다. 이 때 해당 기능이 필요할 때마다 해당 기능을 따로따로 구현하다 보면 코드가 불필요하게 반복되고 길어지게 될겁니다. 이 때 함수를 사용해 이 기능을 구현한다면, 그 기능을 따로 구현할 필요 없이 해당 함수를 호출하는 것만으로 코드를 효율적으로 작성할 수 있게 됩니다.

 

파이썬에서 함수는 아래와 같이 생겼습니다.

def name(a):
    b = 3
    result = a + b
    return result

위에서부터 하나씩 함수에 대해서 알아보겠습니다.

1.2. 함수의 이름과 입력 인자

코드의 맨 윗 줄은 함수의 이름을 정하는 부분입니다.

def name(a):

def 는 definition의 약자로 함수를 정의하겠다는 의미입니다. 그리고 옆에 원하는 함수 이름을 'name' 자리에 쓰면 됩니다. 함수의 이름도 변수의 이름과 같은 규칙을 따릅니다. 이건 지난 변수 포스트를 확인해 주시면 됩니다.

그 옆의 괄호는 입력 인자를 나타냅니다. 여러분이 함수에 입력하려고 하는 변수를 작성하면 됩니다.

def function1(a):
    print(a)
    
def function2():
    print("A")
    
function1(a="Hi")
function1(43)

 

함수의 입력은 위와 같이 사용할 수 있습니다. 입력 되는 변수의 타입은 무엇이 되도 상관 없으며 여러 개의 입력을 받을 수도 있습니다. 혹은 function2()와 같이 입력 인자를 받지 않을 수도 있습니다.

def function2(a, b, c):
    print(a+b+c)
    
function2(3, 5, 7)
function2(a="hello", b=" ", c="World!")

여러 개의 인자가 존재할 경우 마지막 줄과 같이  a, b, c 각 인자에 입력될 변수를 명시할 수도 있고, (function2(a="hello", b=" ", c="world!")) 마지막에서 두번째 줄처럼 앞에서부터 순서대로 자동으로 입력되도록 명시하지 않아도 됩니다. (function2(3, 5, 7))

 

function2() 함수의 경우 입력되는 인자 a, b, c가 문자열과 정수 타입이 섞여 있다면 에러가 발생할 수 있습니다. 이런 경우엔 원하는 인자 타입을 고정해 줄 수 있습니다.

def function2(a: int, b: int, c: int):
    print(a+b+c)

위와 같이 인자 옆에 ': (타입)' 을 넣으면 인자의 타입을 고정할 수 있습니다. 이럴 경우 정한 타입과 다른 타입의 변수가 입력되면 에러를 발생시킵니다.

함수의 입력 인자는 기본값을 지정할 수도 있습니다. 만약 입력되는 값에 거의 변동이 없다면 기본값을 지정해 별다른 값을 입력하지 않더라도 기본 값을 쓸 수 있도록 할 수 있습니다.

def function3(a=3, b=5):
    print(a+b)
    
function3()

위 함수는 입력 인자 a와 b에 기본값 3, 5가 지정되어 있습니다. 그렇기 때문에 입력 인자에 아무것도 전달하지 않는다면 a와 b는 기본값으로 지정되어 결과는 3+5인 8이 출력되게 됩니다.

 

아래와 같이 타입 지정과 기본 값 지정을 동시에 할 수도 있습니다.

def function4(a: int = 3, b: int = 5):
    print(a+b)

 

다른 언어와 달리 파이썬은 타입 지정에 있어 굉장히 자유롭습니다. 이게 코딩할 땐 편하지만 나중에 프로그램을 실행할 때 타입이 맞지 않아 에러가 발생하기 쉽습니다. 그러니 조금 귀찮더라도 타입을 확실히 지정해주는 습관을 들이면 좋습니다.

 

1.3. 함수 내부와 외부 구분

함수는 들여쓰기를 통해 내부와 외부를 구분합니다.

def functionA():
    print("함수의 내부입니다.")
    
print("함수의 외부입니다.")
functionA()

위 코드를 실행하면 결과가 어떻게 출력될까요? "함수의 외부입니다." 가 먼저 출력되고 그 아래에 "함수의 내부입니다."가 출력될 겁니다. 그 이유는 함수 내부의 코드는 그 함수가 호출될 때만 실행되기 때문입니다.

그렇기 때문에 functionA()의 내부는 들여쓰기가 된 부분입니다. 파이썬에서 들여쓰기는 스페이스바로 2칸을 띄우거나 4칸을 띄우면 됩니다.

def functionA():
  print("2칸 띄우기")
  
def functionB():
    print("4칸 띄우기")

2칸을 띄우나 4칸을 띄우나 차이는 없습니다. 그러나 요즘은 가독성을 위해서 4칸을 띄워 쓰는 코드가 많이 보이는 것 같습니다.

Visual Studio Code를 쓰고 있다면 직접 스페이스바로 4칸을 띄울 필요 없이 tab을 한 번 입력해서 한번에 띄어쓸 수 있습니다. 또는 shift+tab을 입력해 들여쓰기를 다시 취소할 수도 있습니다.

혹은 함수를 작성하는 중이라면 ":"을 입력하고 엔터를 치는 순간 자동으로 들여쓰기를 해주는 것을 알 수 있을 겁니다.

1.4. 함수의 출력

함수의 출력은 return을 이용해 출력할 값을 결정할 수 있습니다.

def functionB():
    a = 3
    b = 5
    c = 7
    return b
    
result = functionB()
print(result)

위 코드의 함수 functionB()는 a, b, c 3개의 변수를 갖고 있지만 결과적으로 b만 return하기 때문에 안에서 어떤 일이 벌어지든 최종적으로 출력되는 것은 변수 b의 값인 5입니다.

result = functionB() 코드를 통해 functionB() 함수의 결과를 result 변수에 저장할 수 있습니다. 이렇듯 함수의 return 결과를 다른 변수에 저장할 수 있습니다.

또 입력과 마찬가지로 출력도 반드시 존재할 필요는 없습니다. return을 사용하지 않는다면 함수는 아무것도 출력하지 않습니다.

2. 함수가 갖는 변수

지금까지 봤듯 함수 내부에 변수를 따로 가질 수도 있습니다. 이와 관련해서 중요한 점들을 몇가지 짚고 넘어가고자 합니다.

2.1. 함수 내부의 변수

a = 3

def functionC(b):
    c = 2
    return b ** c
    
print(a)
print(b)
print(c)

위 코드를 한번 살펴보겠습니다. 위 코드를 실행했을 때 변수 a, b, c 중 어떤 값이 출력될까요?

정답은 a만 출력됩니다.

변수 b는 functionC() 함수의 입력 인자를 나타내는 변수입니다. functionC() 안에서만 사용되는 변수이기 때문에 함수 밖에서는 변수 b를 읽을 수 없습니다.

변수 c도 functionC() 안에서 정의된 함수 내부의 변수입니다. 그렇기 때문에 함수 밖에서 변수 c를 읽는 것은 불가능합니다.

이렇듯 함수 안에서 정의된 변수는 그 함수 안에서만 효력을 발휘합니다.

2.2. 함수 외부의 변수

반대로 함수에서 함수 밖에서 정의된 변수에 접근하는 것은 가능합니다.

a = 3

def functionD():
    res = a ** 2
    return res

위 코드에서 변수 a는 functionD() 함수 외부에서 정의되었지만 functionD() 함수에서 변수 a의 값에 접근하는 것이 가능합니다.

이렇게 함수에서 외부의 변수에 접근하는 것은 가능하지만 그 값을 변경하는 것은 불가능합니다.

a = 3

def functionF():
    a = 7
    print("함수 내에서 a의 값 :", a)
    
functionF()
print("함수 밖에서 a의 값 :", a)

위 코드를 보면 변수 a에 3을 저장한 뒤, functionF() 에서 변수 a에 7이라는 값을 새로 넣었습니다. 그러면 외부 변수 a의 값도 변경될까요?

실행해보면 알겠지만 functionF() 안에서 a의 값은 7로 변경되었지만 함수 밖에서 a의 값은 그대로 3인 것을 확인할 수 있습니다.

왜 그렇게 되냐면 함수 내에서 새로 정의한 'a=7' 코드는 함수 외부의 변수 a의 값을 변경한 것이 아니라 functionF() 내에서 새로운 변수 a를 정의한 것이기 때문입니다. 즉, functionF() 내의 변수 a와 functionF() 밖의 변수 a는 서로 다른 변수입니다!

 

정리하자면 함수 내에서 정의된 변수들은 그 함수 내에서만 존재합니다. 따라서 외부에서 접근하는 것이 불가능합니다. 반대로 함수 외부에서 정의된 변수(전역 변수라고 합니다.)들은 함수 내부에서도 접근이 가능합니다.

이런 법칙들이 헷갈린다면 가장 좋은 방법은 함수 내의 변수와 전역 변수의 이름을 겹치지 않게 짓는 것이 좋습니다. 또, 함수 내부에서 외부의 변수에 접근해야 한다면 전역 변수를 그대로 함수에 사용하기 보다는 함수의 입력 인자로 전역 변수를 받아오는 것이 좋습니다.

a = 3
b = 5
c = 8

# 좋은 함수 구현의 예시
# 전역 변수를 사용하고 싶으면 입력 인자로 받는 것이 좋다.
# 함수 내부의 변수 이름은 전역 변수와 겹치지 않는 것이 좋다.
def GoodFunction(input_a, input_b):
    res = input_a + input_b
    return res
    
# 나쁜 함수 구현의 예시
# 전역 변수를 그대로 사용한 함수.
# 전역 변수와 같은 이름의 변수를 함수 내에서도 사용함.
def BadFunction():
    c = a + b
    return c
    
print(GoodFunction(input_a = a, input_b = b))
print(BadFunction())

이런 것은 지키지 않는다 해서 프로그램이 돌아가지 않지는 않지만 헷갈리지 않도록 지켜주면 좋은 약속들입니다.

2.3. 서로 다른 함수간의 관계

앞서 본 바와 마찬가지로, 함수 A에서 정의된 변수는 함수 B에서 사용할 수 없습니다.

def functionA():
    a = 5
    return a
    
def functionB():
    print(a) # functionA()의 변수 a에 접근이 불가능하므로 에러 발생.

하지만 이와 별개로 함수 A에서 함수 B를 사용하는 것은 가능합니다.

def PlusFunction(a, b):
    return a + b
    
def FunctionB(a, b, c):
    res = PlusFunction(a, b)
    res *= c
    return res
    
print(FunctionB(2, 3, 4))

위 코드와 같이 FunctionB()에서 PlusFunction()을 가져다 쓴 것을 확인할 수 있습니다.

 

만약 하나의 함수 내에서만 반복적으로 사용되는 경우라면 함수 내에 함수를 하나 더 정의하는 것도 가능합니다.

def FunctionA(a, b, c):
    def PLUS(a, b):
        return a+b
    res = PLUS(a, b)
    res = PLUS(res, c)
    
    return res
    
print(FunctionA(3, 5, 7))
print(PLUS(3, 5)) # 함수 내부의 함수는 외부에서 사용할 수 없다. 그렇기 때문에 에러 발생.

위와 같이 FunctionA() 내에 PLUS() 함수를 정의한 뒤에 FunctionA() 내에서 반복 사용하는 것이 가능합니다. 그러나 FunctionA()에서 정의한 PLUS() 함수는 FunctionA() 밖에서 사용할 수는 없습니다.

 

부록으로 그렇게 하는 사람은 없겠지만 만약 두 개의 함수가 서로를 참조하는 식으로 코드를 작성한다면...

def name1(a):
    b = name2(a)
    return b
    
def name2(b):
    b = name1(a)
    return b
    
name1(3)

name1() 함수는 name2() 함수를 참조하고 name2() 함수는 name1() 함수를 참조하죠. 그렇기 때문에 name1() 함수가 실행되면 name1()->name2()->name1()->name2()->name1()... 이런 식으로 함수가 무한 실행 되면서 오류가 발생하게 됩니다. 이런 일이 없도록 해야겠죠..?