파이썬 프로그램을 여럿이 개발하는 경우 코드를 어떻게 작성하는 것이 효율적일까?
① 다같이 모여서 한 줄씩 토론하면서 작성하다가 코로나에 걸린다.
② 조별과제처럼 한명이 독박으로 다하다가 과로사로 사망한다.
③ 각자 나눠서 작성하고 마지막에 합친다.
아무래도 프로그래밍 하다 죽는 경우를 없애기 위해선 선택지 ③을 골라야 할 것 같다.
다만 여럿이 같이 만들다 보면 남이 했던 부분을 다시 일일이 코딩하는 경우가 있을 수 있다. 불필요한 중복작업을 방지하고 반복되는 기능을 편리하게 재사용하기 위한 방법이 몇 가지 있는데 함수, 객체, 모듈 등이다. 그 중에서 오늘은 가장 기본적인 파이썬 함수에 대한 정의와 사용방법에 대해 알아본다.
파이썬 함수란?
장문의 파이썬 프로그램을 짤 때 마치 글쓰기처럼 단락을 구분하고 반복되는 부분을 편하게 재사용하기 위한 기능이 바로 함수이다. 함수를 이용하면 프로그램의 흐름을 일목요연하게 볼 수 있고, 인터페이스를 이해하여 어떤 부분에서 문제가 생기는지도 쉽게 파악할 수 있다.
함수를 한마디로 말하자면 어떠한 명령을 수행하는 코드의 덩어리를 지정한 이름으로 정의해놓고 그 기능이 필요할 때마다 이름만 불러서 기능을 가져다 쓰는 것이다.
예를 들어 x, y가 있을 때 x, y의 합과 곱을 출력해주는 명령어를 만들어놨다고 하자. 이것을 함수 A라고 정의해놓는다. 그리고 한참 프로그램을 하다가 이 계산을 또 해야할 일이 있을때 다시 코드를 입력할 필요 없이 A만 불러와서 쓰면 되는 것이다.
수학에서의 함수는 위와 같이 정의된다.
예를 들어 어떤 함수가 f(x)=x+2=y 와 같은 식으로 나타내어 진다고 가정하자. x는 입력값 (input) 이고 f(x)는 입력값에 대해 약속된 연산을 해주는 수식, 그리고 그 결과 y를 출력값으로 낸다. 파이썬에서의 함수도 수학에서의 함수의 개념과 유사하다고 보면 된다.
입력값에 대해 연산을 통해 출력값으로 변환해주는 일종의 인터페이스인 셈이다.
파이썬 함수 선언 문법
그럼 이제 실제로 파이썬 함수를 어떻게 정의하고 사용하는지 공부해보자.
파이썬 함수는 예약어 def를 이용하여 선언한다. 위와 같이 함수 이름과 괄호안에 파라미터 들을 지정해주고 아래에 이 함수가 어떠한 기능을 수행할지를 써준다. “함수이름”은 파라미터들에 대해 수행문과 같은 연산을 하고 반환값을 돌려준다 라는 의미이다.
한가지 중요한 것은 함수에 대한 코드블럭을 작성할 때 위와 같이 def 아래줄들은 모두 indentation (들여쓰기)로 작성한다. 코드 편집기에서 tab (탭 키)를 눌러서 라인을 맞추면 된다. 함수를 선언하는 코드를 직접 실습해보자. 프로그래밍은 자기가 직접 해보고 익히는 수밖에…
이렇게 caculate_rectangle_area 라는 긴 이름의 함수명을 정의하고 x, y 파라미터에 대해 곱하기를 해주는 수행문을 작성하였다. 마지막에 return은 이 함수가 끝날 때 연산한 어떤 값을 반환해준다는 의미인데, result에 x와 y의 곱한 값을 넣어주고 그 result 값을 결과물로 내놓으며 마친다는 의미이다.
아래에 10, 20 값을 가지는 두 가지 변수를 지정하고 그 두가지 변수를 함수의 인수로 불러오면 미리 지정한 연산에 의해 10*20=200의 값이 return되었고 그 값을 print해서 확인하였다.
구글링 중 어떤 문서를 보면 위와 같이 함수 선언 부분에 arguments가 들어가는 것으로 써놓았는데 정확히는 잘못되었다. 이게 사람마다 제각각으로 써놔서 헷갈리는 부분이다. 아래와 같이 정리해둔다.
From a function’s perspective:
함수의 관점에서 :
A parameter is the variable listed inside the parentheses in the function definition.
매개변수는 함수 정의시 괄호안에 나열되는 변수이다.
→ 함수의 입력 값 인터페이스
An argument is the value that are sent to the function when it is called.
인수는 함수가 호출될 때 보내지는 값이다.
→ 실제로 파라미터에 입력된 값
arguments 인수의 종류
함수를 정의한 뒤 호출해서 사용할 때 사용되는 인수, arguments의 종류에 대해 알아본다.
① Required Arguments
요구 인수는 누락되면 에러가 발생하는 꼭 필요한 인수이다. 위와 같이 함수명(매개변수) 형태로 정의해주었기 때문에 호출할 때도 함수명(인수) 형태로 불러와야 인수에 대해 수행하고 값을 반환한다.
만약 여기서 printstring() 형태로 함수를 호출하고 인수명을 기입하지 않는다면, 다음과 같은 에러가 발생하게 된다.
TypeError: printstring() missing 1 required positional argument: ‘str’
② Keyword Arguments
키워드 인수는 매개변수를 여러개 지정했을 때 보통 사용하는데 여기서는 예시로 한가지만 지정하였다. 매개변수 name이 지정되었는데 함수를 호출할 때 name에 무엇이 들어갈지 직접 지정해주는 방식이다. 이를 키워드 인수라 한다.
매개변수 여러개를 지정하고 키워드 인수로 호출할 때 순서는 일치하지 않아도 상관없다. 위와 같이 name1,2,3순으로 지정했으나 호출시에는 3,1,2 순으로 입력해도 결과는 같다.
다만 직접 지정해 줄 때 선언되지 않은 매개변수명을 입력하면 다음과 같은 에러가 발생한다. 예를 들어 매개변수명 name1 이라고 했을 경우
TypeError: printdata() got an unexpected keyword argument ‘name1’
③ Default Arguments
기본 인수는 함수 호출시 값이 제공되지 않으면 매개변수의 기본값을 사용하는 인수이다. 위 예시와 같이 함수 호출시 매개변수 salary 값을 3500으로 기본값 지정을 해줄 수 있는데, 나중에 함수 호출할 때 인수를 하나만 지정하면 다른 하나는 기본값을 결과물로 낸다.
당연히 두 개의 인수를 입력하면 매개변수의 기본값은 무시되고 새로운 값으로 위와 같이 출력되는 것을 알 수 있다.
④ Variable-Length Arguments
하다보면 매개변수는 3개 입력했는데 인수를 5개 입력하는 경우가 있다. 이럴 경우 다음과 같은 에러가 난다.
매개변수의 개수를 사전에 지정해놓지 않고 필요한 만큼 입력되는 인수에 대해 연산을 수행하고 싶다면 variable-length 인수 형태를 이용해서 다음과 같이 하면 된다.
파라미터를 지정할 때 *을 붙여주고, for 문을 이용해 nos의 모든 요소 n에 대해 각각 수행문을 이행하도록 하였다. 결과 부분을 보면 인수가 두 개 입력되면 두개를 출력하고, 세 개 입력되면 세개를 출력하는 것을 볼 수 있다.
가변길이 인수 입력방법은 두 가지를 사용할 수 있다.
- 키워드가 아닌 변수
- 키워드 변수
1번의 경우를 파이썬 자료형 중 하나로 튜플 (tuple) 이라고 하는데 이는 나중에 다시 자세히 학습한다.
파라미터와 반환값 유무
파이썬 함수는 파라미터 (parameter 매개변수) 그리고 반환값 (return value) 유무에 따라서도 형태를 나눌 수 있다.
parameter 없음 | parameter 있음 | |
반환 값 없음 | parameter 없이 수행문만 수행하고 결과 값 반환 없음 | parameter를 가지고 수행문을 수행한 뒤 반환되는 결과값은 없음 |
반환 값 있음 | parameter 없이 수행문만 수행하고 결과 값 반환해줌 | parameter를 가지고 수행문을 수행한 뒤 결과값을 반환함 |
위 표와 같이 반환 값 (return value) 그리고 파라미터 (parameter) 유무에 따라 4가지 형태로 분류하였다.
각각의 경우에 함수가 어떻게 동작하는지 실제 코딩 예시를 통해서 살펴보자.
위에서 부터 4개의 함수를 정의하였다.
각각
파라미터X 리턴X
파라미터O 리턴X
파라미터X 리턴O
파라미터O 리턴O
이다.
결과값을 보면, 첫번째 파라미터X 리턴X 함수의 경우 수행문 print에 의해 8*10을 출력한다. 입력값에 대해 수행하는 명령이 아니라 그냥 80을 출력하도록 만들어진 별 의미없는 함수이다. 결과부분을 보면 함수 내 print문에 의해서 80을 화면에 출력하고, 반환값이 없기 때문에 print (함수명) 형태로 출력시 결과가 None이 나옴을 알 수 있다.
두 번째 파라미터O 리턴X 함수의 경우 파라미터가 있기 때문에 함수 호출시 인수를 같이 입력해 주어야 한다. 인수를 입력하면 수행문에 의해 그 값의 곱한값을 화면에 출력하고 마찬가지로 반환값이 없기 때문에 함수 값을 호출하면 None이 나오게 된다.
즉 반환값 (return value)이 없기 때문에 함수 자체는 어떠한 값을 저장해서 가지고 있는게 없다. 단지 함수내의 수행문에 의해 print로 화면에 출력만 해주도록 되어있다.
반면에 반환값을 가지는 세번째 네번째 함수의 경우에는 함수를 호출시 어떤 값이 나옴을 알 수 있다.
프린트와 리턴의 차이를 정확하게 이해하고 넘어가야 하는데, 프린트는 말그대로 화면에 출력해서 보여준다는 의미. 그리고 리턴은 어떠한 값을 결과물로 여겨서 메모리 주소에 저장해 놓는다는 뜻이다.
프린트는 화면에만 보여줄 뿐 실제로 메모리 주소에 어떤값을 저장해 놓지 않는다. 위에서 리턴값 없는 함수예제로 살펴봤듯이 리턴값이 없으면 결과물이 없이 비어있는 속빈강정(?) 이다. 이것은 None으로 나타내어진다.
반면에 리턴값이 있다면 실제로 연산의 결과물로써 어떤 값을 저장해놓게 되는데 프린트문이 있으면 출력을 하는 것이고 없으면 그냥 값만 가지고 있게 된다. 즉, 프린트문이 없어서 화면에 출력되는 내용이 없다고 하더라도 실제로는 연산이 이루어지고 그 결과값을 잘 저장해놓고 있는 것이다.
위 예제에서 함수 자체만 입력해서 결과를 보면, print 수행문이 있는 위에 두개 함수는 화면에 80을 출력하였지만 실제로 함수의 결과물은 None이다.
아래 두 개의 함수는 반환값 (리턴값)을 가지므로 함수의 결과물은 80을 가지고 있을 것이다. 다만 프린트 문이 없으므로 세 번째 함수는 화면에 출력되는게 없고, 네번째 함수 파라미터가 있는 경우에는 인수의 연산결과 리턴값을 화면에도 보여주는 차이가 있다.