본문 바로가기
프로그래밍/Python

파이썬 문법 4 - 함수(function)

by pentode 2018. 4. 4.

파이썬에서 함수를 정의하고 사용하는 방법에 대해서 알아 봅니다. 함수를 코드를 모아 두었다가 재사용할 수 있는 방법입니다. 이미 앞에서도 함수를 사용했었습니다. 바로 글을 출력하기 위한 print() 함수 입니다.

 

>>> print('Hello, Python!')
    Hello, Python!
>>>

 

이러한 미리 만들어져 있는 많은 유용한 함수들이 많이 있습니다. 이번에 해볼 것은 자신이 필요한 함수를  정의해서 사용하는 것입니다.


두 값을 더하는 간단한 함수를 하나 만들어보겠습니다.

 

파이썬 함수

 

>>> def add(arg1, arg2):
        c = arg1 + arg2
        return c
>>> print(add(2, 3))
    5
>>>


- 함수 정의의 시작을 def 로 시작합니다.
- 그 뒤에 공백으로 띄우고 함수명이 나옵니다. 예에서는 add 가 함수명 입니다.
- 함수명뒤에 소괄호를 사용하여 함수로 보낼 인자들의 리스트가 나옵니다. 인자들은 없을수도 있고, 다수가 있을 수도 있습니다.
- 인자 리스트를 닫는 소괄호 뒤에 콜론(:)이 나옵니다. 여기까지가 함수의 signature의 작성이 끝났습니다.
- 함수의 본체는 들여쓰기를 함으로써 본체임을 알립니다. c = arg1 + arg2 부터의 부분이 본체가 되겠습니다.
- 함수는 값을 반환할 수 있습니다. 물론 반환하지 않을 수도 있습니다. 값을 반환하기 위해서는 return 문장을 사용합니다. 예에서는 return c 부분 입니다.
- 함수의 끝은 따로 지정하는게 없습니다. 들여쓰기가 def 와 같은레벨로 나오면 거기까지가 함수의 끝입니다.

 

 

다음 예는 단순히 한문장을 출력하는 인자도 없고, 반환값도 없는 함수를 보여주고 있습니다. 함수 이름은 text 입니다.

 

>>> def text():
        print('print test string')

>>> text
    <function text at 0x00000261ECF96560>

>>> text()
    print test string

>>> content = text
>>> content
    <function text at 0x00000261ECF96560>

>>> content()
    print test string
>>>

 

실행된 결과에서 보면 text 함수를 끝에 괄호 없이 실행하면 <function text at 0x00000261ECF96560>와 같은 값이 출력되고 있습니다. text() 를 실행하면 정상적으로 텍스트가 출력이 됩니다.

 

이것이 의미하는 바는 함수 이름은 실제 함수가 있는 곳에 대한 주소를 가진다는 것입니다.

 

content = text 에서 함수의 주소를 다른 변수에 복사했습니다. 이제 content() 를 실행하면 text() 를 실행한것과 동일한 결과가 나옵니다. 같은 함수가 실행되었기 때문입니다.


다른 언어에서는 함수로 인자전달시 참조에 의한 전달(Pass By Reference)로 보내게 되면 함수내에서 그 참조가 가리키고 있는 값을 변경하면 함수를 호출한 외부의 변수가 가리키는 곳의 값이 변경되므로 외부에 영향을 미치게 됩니다.

 

파이썬에서 함수의 인자로 값을 전달할 때는 다른 언어에서와는 조금 다른 방식으로 동작합니다. 파이썬의 함수 인자 전달 방식은 Pass By Object Reference 라고 합니다. 참조를 전달하기는 하지만 동작방식이 좀 다릅니다.

 

인자로 보낸 변수가 불변(immutable)이라면, 함수내에서 변경할 때 참조가 가리키고 있는 값을 변경하지 않고, 새로운 객체를  생성하고, 변수가 가지고 있는 주소를 새로 생성된 객체의 주소로 변경합니다. 함수내부의 참조변수는 지역 변수이므로 그 참조값이 변하더라도 외부에 영향을 주지 않습니다.

 

문자열은 불변이므로 문자열을 전달하는 예를 보겠습니다.

 

>>> def foo(x):
        x = '다른 문자열'
        print(x)

>>> bar = '원래 문자열'
>>> foot(bar)
    다른 문자열
>>> bar
    '원래 문자열'
>>>

 

함수 foo 는 bar의 참조를 넘겨 받습니다. 함수 foo 내부에서는 x 라는 지역변수로 이 참조 주소를 유지합니다. 함수내에서 이 값을 변경하려고 하지만 문자열은 불변이므로 코드 x = '다른 문자열' 은 '다른 문자열' 값을 저장하는 객체를 새로 만들고 구 참조 주소를 x 에 저장 합니다. 그러므로 함수 밖의 bar 가 가리키고 있는 값을 변경되지 않습니다. 마치 값에 의한 전달(Pass By Value) 처럼 동작합니다.

 

인자로 보낸 변수가 변경 가능한(mutable)것이라면, 함수내에서 참조가 가리키는 값을 변경하게 됩니다. 그러므로 외부에도 영향을
주게 됩니다.

 

변경가능인 리스트를 인자로 넘기는 예를 보겠습니다.

 

>>> def foo(x):
        x.append(1)
        print(x)

>>> bar = [0]
>>> foo(bar)
    [0, 1]
>>> bar
    [0, 1]
>>>

 

함수 foo 는 리스트의 참조를 받아서 1을 추가합니다. 함수의 인자 변수인 x 는 함수 호출시 넘겨진 bar 의 참조 주소를 가지고 있습니다. 이 참조주소에 x.append(1) 을 하면 같은 주소를 가지고 있는 bar의 내용도 변하게 됩니다.


이번에는 함수 인자에 기본값을 주는 방법을 알아보겠습니다.

 

>>> def foo(a = 2, b = 3):
        print(a + b)

>>> foo()
    5
>>> foo(3)
    6
>>>

 

괄호안의 인자 리스트에 인자를 선언시 a = 2 처럼 기본값을 줄 수 있습니다. 기본값을 가지는 인자는 실제 함수 호출시 생략할 수 있고, 생략하게 되면 정의된 기본 값이 사용됩니다. 기본 값이 주어진 인자 오른쪽에 기본값이 없는 인자가 나올 수 없습니다.


이번에는 가변 인자에 대해 알아보겠습니다.

 

>>> def foo(*x):
        for v in x:
            print(v)

>>> foo('this', 'is', 'test')
    this is test
>>>

 

가변인자는 *x 처럼 앞에 *을 붙여 정의합니다. 이 인자는 tuple 로 처리됩니다. 함수 내부에서 for 문으로 tuple 로 받아 들여진 인자를 출력하고 있습니다.

 

또다른 가변인자로 ** 를 붙이는 것이 있는데, 이것은 dictionary 로 처리 됩니다.

 

>>> def foo(**x):
        for key in x.keys():
            print(key + ":" + x[key])

>>> foo(name="홍길동", tel="010-2345-7896")
    name:홍길동
    tel:010-2345-7896
>>>

 

함수를 호출할때 인자를 키와값의 쌍으로 줄 수 있습니다.

반응형