함수

함수를 사용하는 이유는 무엇일까?

프로그래밍을 하다 보면 똑같은 내용을 반복해서 작성하고 있는 자신을 발견할 때가 종종 있다. 이때가 바로 함수가 필요한 때이다. 즉, 반복되는 부분이 있을 경우 “반복적으로 사용되는 가치 있는 부분”을 한 뭉치로 묶어서 “어떤 입력값을 주었을 때 어떤 결과값을 돌려준다”라는식의 함수로 작성해야 한다.

파이썬 함수의 구조

파이썬 함수의 구조는 다음과 같다.

def 함수명(입력 인수):
	<수행할 문장1>
	<수행할 문장2>
	...
  • def는 함수를 만들 때 사용하는 예약어이며, 함수명은 함수를 만드는 사람이 임의로 만들 수 있다.
>>> def sum(a, b):
... 	return a+b
...
>>>
  • 위의 함수는 이렇게 해석할 수 있다.

    • 이 함수의 이름(함수명)은 sum이고 입력 인수로 2개의 값을 받으며 결과값은 2개의 입력값을 더한 값이다

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

함수는 들어온 입력값을 받아 어떤 처리를 하여 적절한 결과값을 돌려준다.

입력값–>함수–>리턴값

일반적인 함수

입력값이 있고 결과값이 있는 함수가 일반적인 함수이다.

def 함수이름(입력인수):
	<수행할 문장>
	...
	return 결과값

입력값이 없는 함수

입력값이 없는 함수가 존재할까? 당연히 존재한다.

>>> def say():
... 	return 'Hi'
...
>>>
  • say라는 이름의 함수를 만들었다. 그런데 입력 인수 부분을 나타내는 함수명 뒤의 괄호 안이 비어있다. 이 함수는 어떻게 사용하는걸까?
>>> a = say()
>>> print(a)
Hi
  • 위의 함수를 쓰기 ㄹ위해서는 say()처럼 괄호 안에 아무런 값도 넣지 않아야 한다.

결과값이 없는 함수

결과값이 없는 함수 역시 존재한다

>>> def sum(a, b):
... 	print("%d, %d의 합은 %d입니다." % (a, b, a+b))
...
>>>
  • 결과값이 없는 함수는 호출해도 돌려주는 값이 없기 때문에 다음과 같이 사용한다.
>>> sum(3, 4)
3, 4의 합은 7입니다.
  • 위의 예제에서 결과값은 당연히 없다. 결과값은 오직 return 명령어로만 돌려받을 수 있다.
>>> a = sum(3, 4)
>>> print(a)
None
  • a의 값은 None이다. None이란 거짓을 나타내는 자료형이라고 언급한 적이 있다. sum 함수처럼 결과값이 없을 때 a = sum(3, 4)처럼 쓰게 되면 함수 sum은 리턴값으로 a 변수에 None을 돌려준다. 이것을 가지고 결과값이 있다고 생각하면 안된다.

입력값도 결과값도 없는 함수

>>> def say():
... 	print('Hi')
...
>>>
  • 입력 인수를 받는 곳도 없고 return문도 없으니 입력값도 결과값도 없는 함수이다.

이 함수를 사용하는 방법은 단 한가지이다.

>>> say()
Hi

즉, 입력값도 결과값도 없는 함수는 다음과 같이 사용한다.

함수명()

입력값이 몇 개가 될지 모를 때는 어떻게 해야 할까?

입력값이 여러 개일 때 그 입력값들을 모두 더해 주는 함수를 생각해보자. 하지만 몇개가 입력될지 모를 때는 어떻게해야할까? 파이썬은 이런 문제를 해결하기 위해 다음과 같은 방법을 제공한다.

def 함수이름(*입력변수):
	<수행할 문장>
	...

여러 개의 입력값을 받는 함수 만들기

  • sum_many(1, 2)이면 3을, sum_many(1,2,3)이면 6을, sum_many(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)이면 55를 돌려주는 함수를 만들어 보자
>>> def sum_many(*args): 
...     sum = 0 
...     for i in args: 
...         sum = sum + i 
...     return sum 
... 
>>>
  • 위에서 만든 sum_many라는 함수는 입력값이 몇 개든 상관이 없다. *args처럼 입력 변수명 앞에 *을 붙이면 입력값들을 전부 모아서 튜플로 만들어 주기 때문이다.

  • 만약 sum_many(1, 2, 3)처럼 이 함수를 쓰면 args는 (1, 2, 3)이 되고, sum_many(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)처럼 쓰면 args는 (1, 2, 3, 4, 5, 6, 7, 8, 9, 10)이 된다. 여기서 *args라는 것은 임의로정한 변수명이다. *pey, *python처럼 아무 이름이나 써도 된다.

실제로 이 함수를 직접 입력해보자

>>> result = sum_many(1,2,3)
>>> print(result)
6
>>> result = sum_many(1,2,3,4,5,6,7,8,9,10)
>>> print(result)
55
  • sum_many(1,2,3)으로 함수를 호출하면 6을 리턴하고, sum_many(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)을 대입하면 55를 리턴한다.

함수의 결과값은 언제나 하나이다

>>> def sum_and_mul(a, b):
... 	return a+b, a*b
  • sum_and_mul 함수는 2개의 입력 인수를 받아 더한 값과 곱한 값을 돌려주는 함수이다.

이 함수를 다음과 같이 호출하면 어떻게 될까?

>>> result = sum_and_mul(3,4)
  • 결과값은 a+ba*b 2개인데 결과값을 받아들이는 변수는 result 하나만 쓰였으니 오류가 발생하지 않을까? 당연한 의문이다. 하지만 오류는 발생하지 않는다. 그 이유는 함수의 결과값은 2개가 아니라 언제나 1개라는 데 있다.

따라서 result 변수는 다음과 같은 값을 갖게 된다

result = (7, 12)
  • 즉, 결과값으로 (7, 12)라는 튜플 값을 갖게 되는 것이다.

만약 이 하나의 튜플값을 2개의 결과값처럼 받고 싶다면 다음과 같이 함수를 호출하면 된다!

>>> sum, mul = sum_and_mul(3, 4)
  • 이렇게 호출하면 sum, mul=(7,12)가 되어 sum은 7이 되고 mul은 12가 된다.

입력 인수에 초깃값 미리 설정하기

다음은 인수에 초깃값을 미리 설정해 주는 경우이다!

def say_myself(name, old, man=True): 
    print("나의 이름은 %s 입니다." % name) 
    print("나이는 %d살입니다." % old) 
    if man: 
        print("남자입니다.")
    else: 
        print("여자입니다.")
  • 위의 함수를 보면 입력 인수가 name, old, man=True 이렇게 3개다. 그런데 낯선 것이 나왔다. man=True처럼 입력 인수에 미리 값을 넣어 준 것이다. 이것이 바로 함수의 인수 초깃값을 설정하는 방법이다

함수 입력 인수에 초깃값을 설정할 때 주의할 사항

만약 위에서 본 say_myself 함수를 다음과 같이 만들면 어떻게 될까?

def say_myself(name, man=True, old): 
    print("나의 이름은 %s 입니다." % name) 
    print("나이는 %d살입니다." % old) 
    if man: 
        print("남자입니다.") 
    else: 
        print("여자입니다.")
  • 이전 함수와 바뀐 부분은 초깃값을 설정한 인수의 위치이다. 결론적으로는 이것은 함수를 실핼할 때 오류가 발생한다.

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

함수 안에서 사용할 변수의 이름을 함수 밖에서도 동일하게 사용한다면 어떻게 될까?

# vartest.py
a = 1
def vartest(a):
    a = a +1

vartest(a)
print(a)
  • 당연히 vartest 함수에서 변수 a의 값에 1을 더했으니까 2가 출력되어야 할 것 같지만 프로그램 소스를 작성해서 실행시켜 보면 결과값은 1이 나온다. 그 이유는 함수 안에서 새로 만들어진 변수는 함수 안에서만 사용되는 “함수만의 변수”이기 때문이다. 즉, def vartest(a)에서 입력 인수를 뜻하는 변수 a는 함수 안에서만 사용되는 변수이지 함수 밖의 변수 a가 아니라는 뜻이다.

함수 안에서 함수 밖의 변수를 변경하는 방법

1. return 이용하기

# vartest_return.py
a = 1 
def vartest(a): 
    a = a +1 
    return a

a = vartest(a) 
print(a)
  • vartest 함수는 입력으로 들어온 값에 1을 더한값을 돌려준다. 따라서 a = vartest(a)라고 대입하면 a가 vartest 함수의 결과값으로 바뀐다.

2. global 명령어 사용하기

# vartest_global.py
a = 1 
def vartest(): 
    global a 
    a = a+1

vartest() 
print(a)
  • 두 번째 방법은 global이라는 명령어를 이용하는 방법이다. 위의 예에서 볼 수 있듯이 vartest 함수 안의 global a라는 문장은 함수 안에서 함수 밖의 a 변수를 직접 사용하겠다는 뜻이다.

사용자 입력과 출력

우리들이 사용하는 대부분의 완성된 프로그램은 사용자의 입력에 따라 그에 맞는 출력을 내보낸다. 대표적인 예로, 게시판에 글을 작성한 후 “확인”버튼을 눌러야만(입력) 우리가 작성한 글이 게시판에 올라가는(출력)것을 들 수 있다.

사용자 입력 » 처리(프로그램, 함수 등) » 출력

사용자 입력

input의 사용

>>> a = input()
Life if too short, you need python
>>> a
'Life is too short, you need python'
>>>
  • input은 입력되는 모든 것을 문자열로 취급한다.

프롬프트를 띄워서 사용자 입력 받기

사용자에게 입력을 받을 때 “숫자를 입력하세요”라든지 “이름을 입력하세요”라는 안내 문구 또는 질문이 나오도록 하고 싶을 때가 있다. 그럴 때는 input()의 괄호 안에 질문을 입력하여 프롬프트를 띄워주면 된다.

input("질문 내용")

큰따옴표(“)로 둘러싸인 문자열은 + 연산과 동일하다

>>> print("life" "is" "too short") # ①
lifeistoo short
>>> print("life"+"is"+"too short") # ②
lifeistoo short
  • 위의 예에서 1 과 2 는 완전히 동일한 결과값을 출력한다. 즉, 따옴표로 둘러싸인 문자열을연속해서 쓰면 + 연산을 한 것과 같다.

문자열 띄어쓰기는 콤마로 한다

>>> print("life", "is", "too short")
life is too short

한 줄에 결과값 출력하기

>>> for i in range(10):
...     print(i, end=' ')
...
0 1 2 3 4 5 6 7 8 9
  • 한 줄에 결과값을 계속 이어서 출력하려면 입력 인수 end를 이용해 끝 문자를 지정해야 한다.

파일 읽고 쓰기

파일 생성하기

다음 소스 코드를 에디터로 작성해서 저장한 후 실행해 보자. 프로그램을 실행한 디렉터리에 새로운 파일이 하나 생성된 것을 확인할 수 있을 것이다

f = open("새파일.txt", 'w')
f.close()
  • 파일을 생성하기 위해 우리는 open이라는 파이썬 내장 함수를 사용했다. open 함수는 다음과 같이 “파일 이름”과 “파일 열기 모드”를 입력값으로 받고 결과값으로 파일 객체를 돌려준다.
파일 객체 = open(파일 이름, 파일 열기 모드)
파일열기모드 설명
r 읽기모드 - 파일을 읽기만 할 때 사용
w 쓰기모드 - 파일에 내용을 쓸 때 사용
a 추가모드 - 파일의 마지막에 새로운 내용을 추가 시킬 때 사용
  • 파일을 쓰기 모드로 열게 되면 해당 파일이 이미 존재할 경우 원래 있던 내용이 모두 사라지고, 해당 파일이 존재하지 않으면 새로운 파일이 생성된다

파일을 쓰기 모드로 열어 출력값 적기

이번에는 에디터를 열고 프로그램의 출력값을 파일에 직접 써 보자.

# writedata.py
f = open("C:/Python/새파일.txt", 'w')
for i in range(1, 11):
    data = "%d번째 줄입니다.\n" % i
    f.write(data)
f.close()

위의 프로그램을 다음 프로그램과 비교해 보자.

for i in range(1, 11):
    data = "%d번째 줄입니다.\n" % i
    print(data)
  • 두 프로그램의 다른 점은 data를 출력하는 방법이다. 두 번째 방법은 우리가 계속 사용해 왔던 모니터 화면에 출력하는 방법이고, 첫 번째 방법은 모니터 화면 대신 파일에 결과값을 적는 방법이다.

프로그램의 외부에 저장된 파일을 읽는 여러가지 방법

readline()함수 이용하기

첫 번째 방법은 readline() 함수를 이용하는 방법이다.

# readline.py
f = open("C:/Python/새파일.txt", 'r')
line = f.readline()
print(line)
f.close()
  • 위 예는 f.open(“새파일.txt”, ‘r’)로 파일을 읽기 모드로 연 후 readline()을 이용해서 파일의 첫 번째 줄을 읽어 출력하는 경우이다. 이전에 만들었던 새파일.txt를 수정하거나 지우지 않았다면 위 프로그램을 실행시켰을 때 새파일.txt의 가장 첫 번째 줄이 화면에 출력될 것이다.
1번째 줄입니다.

readlines() 함수 이용하기

f = open("C:/Python/새파일.txt", 'r')
lines = f.readlines()
for line in lines:
    print(line)
f.close()

read() 함수 이용하기

f = open("C:/Python/새파일.txt", 'r')
data = f.read()
print(data)
f.close()
  • f.read()는 파일의 내용 전체를 문자열로 리턴한다. 따라서 위 예의 data는 파일의 전체 내용이다.

파일에 새로운 내용 추가하기

# adddata.py
f = open("C:/Python/새파일.txt",'a')
for i in range(11, 20):
    data = "%d번째 줄입니다.\n" % i
    f.write(data)
f.close()

위 예는 새파일.txt라는 파일을 추가 모드(‘a’)로 열고 write를 이용해서 결과값을 기존 파일에 추가해 적는 예이다. 여기서 추가 모드로 파일을 열었기 때문에 새파일.txt라는 파일이 원래 가지고 있던 내용 바로 다음부터 결과값을 적기 시작한다.

with문과 함께 사용하기

f = open("foo.txt", 'w')
f.write("Life is too short, you need python")
f.close()
  • 파일을 열면 위와 같이 항상 close해 주는 것이 좋다. 하지만 이렇게 파일을 열고 닫는 것을 자동으로 처리할 수 있다면 편리하지 않을까?
with open("foo.txt", "w") as f:
    f.write("Life is too short, you need python")
  • 파이썬의 with문이 바로 이런 역할을 해준다. 위의 예는 with문을 이용해서 위 예제를 다시 작성한 모습이다.