4.6. 함수 정의하기
Defining Functions
We can create a function that writes the Fibonacci series to an arbitrary boundary:
우리는 임의의 경계에 피보나치 시리즈를 쓰는 함수(=기능)를 만들 수 있다.
>> def fib(n): # n이라는 수까지 피보나치 수열을 만드는 함수를 설정한다.
... """Print a Fibonacci series up to n."""
... a, b = 0, 1
... while a < n:
... print(a, end=' ')
... a, b = b, a+b
... print()
...
>>> # 이제 우리가 설정한 함수를 부르기만 하면 된다.
... fib(2000) # 함수 fib가 2000까지의 피보나치 수열을 만들어 낸다.
0 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597
The keyword def introduces a function definition. It must be followed by the function name and the parenthesized list of formal parameters. The statements that form the body of the function start at the next line, and must be indented.def
는 definition 의 줄임말이다. def
뒤에 함수의 이름을 적고, 뒤이은 괄호 안에는 함수가 적용될 '형식 매개 변수'를 적는다. 함수의 몸체(본문)가 되는 문장은 def 함수이름(형식매개변수)
다음줄에 적어야 하고, 반드시 들여써야 한다.
The first statement of the function body can optionally be a string literal; this string literal is the function’s documentation string, or docstring. (More about docstrings can be found in the section Documentation Strings.) There are tools which use docstrings to automatically produce online or printed documentation, or to let the user interactively browse through code; it’s good practice to include docstrings in code that you write, so make a habit of it.
함수의 본문 첫 줄은 원한다면 함수에 대해 설명하는데 사용할 수 있다. 이러한 문장을 함수에 대한 documentation string 또는 docstring 이라 한다. docstring 에 대해서는 Documentation Strings에서 더 자세하게 알아볼 수 있다. (*아직 링크 연결되지 않음) docstring을 통해 자동적으로 온라인 또는 인쇄된 설명서로 연결하거나, 사용자에게 코드를 통해 상호적으로 검색할 수 있게 하는 기능도 있다. 작성한 코드에 대해 docstring을 남기는 것이 좋다. docstring 작성을 습관화하자.
The execution of a function introduces a new symbol table used for the local variables of the function. More precisely, all variable assignments in a function store the value in the local symbol table; whereas variable references first look in the local symbol table, then in the local symbol tables of enclosing functions, then in the global symbol table, and finally in the table of built-in names. Thus, global variables cannot be directly assigned a value within a function (unless named in a global statement), although they may be referenced.
함수의 실행(execution)은 새로운 symbol table을 도입한다. 이 symbol table은 함수의 지역적 변수로 사용된다. 좀더 정확하게 말하자면, 함수 안에 집어넣어진 모든 변수들은 그 함수의 지역적 symbol table 에 저장된다. 변수에 대한 자료가 지역적 symbol table에 먼저 나타나고, 그 다음은 enclosing function의 지역적 local table, 마지막으로는 파이썬에 내장된 이름의 table이 온다. 따라서 대중적으로 사용되는 변수는 (global statement로 이름을 짓지 않는 한)함수와 함께 직접적으로 값을 지정받을 수 없다. 물론 참고는 해도 된다.
The actual parameters (arguments) to a function call are introduced in the local symbol table of the called function when it is called; thus, arguments are passed using call by value (where the value is always an object reference, not the value of the object). 1 When a function calls another function, a new local symbol table is created for that call.
함수호출에 대한 '실제 매개 변수(인수)'가, 함수가 호출될 때, 호출된 함수의 지역적 symbol table에 도입된다. 그러므로 인수는 언제나 값으로 호출되어 전달된다. (그 값은 언제나 객체가 아니라 객체의 자료이다.) 1 함수가 또다른 함수를 불러냈을 때(호출했을 때) 새로운 지역적 symbol table이 그 호출을 위해 만들어진다.
A function definition introduces the function name in the current symbol table. The value of the function name has a type that is recognized by the interpreter as a user-defined function. This value can be assigned to another name which can then also be used as a function. This serves as a general renaming mechanism:
'함수 정의'는 현재 존재하는 symbol table 에 함수이름을 집어넣는다. 이러한 방식의 함수 이름값은 인터프리터에게 사용자가 정의한 함수(사용자 정의 함수)로 인식된다. 이렇게 정의된 함수의 이름은 그 자체로 또 다른 이름을 할당받을 수도 있다. 이러한 기능은 일반적인 이름다시짓기(재명명) 원리를 지원한다.
>>> fib
<function fib at 10042ed0>
>>> f = fib # fib라는 이름의 함수에 다시 f라는 이름을 지어주었다.
>>> f(100) # fib와 동일하게 작동한다.
0 1 1 2 3 5 8 13 21 34 55 89
Coming from other languages, you might object that fib is not a function but a procedure since it doesn’t return a value. In fact, even functions without a return statement do return a value, albeit a rather boring one. This value is called None (it’s a built-in name). Writing the value None is normally suppressed by the interpreter if it would be the only value written. You can see it if you really want to using print():
다른 언어를 사용하다 파이썬을 사용하게 되었다면, 위 예시의 fib
(피보나치 수열 생성 함수)은 fib
이 값을 반환하지 않을 때 함수가 아니라 '절차'라고 부르는 게 맞다고 생각할 수 있다. 사실 좀 지루하긴 하지만, 함수는 return
문법 없이도 값을 내보낼 수 있다. 이렇게 만들어진 값은 None
이라고 불린다. (이렇게 불리도록 파이썬에 미리 설정되어 있다.) 이 것이 함수에 대한 유일한 값이 될 경우 인터프리터는 대개 이 값을 보여주지 않는다. 꼭 이 값을 보고싶다면 print()
를 사용해야 한다.
>>> fib(0)
>>> print(fib(0))
None
It is simple to write a function that returns a list of the numbers of the Fibonacci series, instead of printing it:
피보나치 수열의 리스트를 값으로 돌려주는 함수를 작성하는 것이 그 리스트를 직접 작성하는 것보다 간단하다.
>>> def fib2(n): # n이라는 수 까지의 피보나치 수열을 값으로 돌려준다.
... """n이라는 수 까지의 피보나치 수열을 값으로 내보낸다. """ # docstring
... result = [] # 우선 값이 저장될 빈 리스트를 하나 만들어 둔다.
... a, b = 0, 1
... while a < n:
... result.append(a) # a<n 이라는 조건이 맞을 경우 위에서 만든 빈 리스트에 a가 추가된다.
... a, b = b, a+b # a, b의 값을 b, a+b로 변경하고 다시 조건을 테스트 한다.
... return result # while 문법이 작동을 끝내면(조건이 맞지 않게 되면) 결과를 내보낸다.
...
>>> f100 = fib2(100) # 함수를 호출한다. (fib2라는 함수를 불러와 100이라는 인수를 준다.)
>>> f100 # f100을 입력하면 파이썬이 값을 알려준다.
[0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89]
This example, as usual, demonstrates some new Python features:
이 예시는 파이썬의 새로운 기능을 보여주고 있다.
- The return statement returns with a value from a function. return without an expression argument returns
None
. Falling off the end of a function also returnsNone
.- return 문은 함수의 결과를 보여준다.(반환한다.) return은 표현식 인수가 없는 경우
None
을 보여주고, 함수가 작동을 멈춘 경우도None
을 보여준다.
- return 문은 함수의 결과를 보여준다.(반환한다.) return은 표현식 인수가 없는 경우
- The statement result.append(a) calls a method of the list object result. A method is a function that ‘belongs’ to an object and is named obj.methodname, where obj is some object (this may be an expression), and methodname is the name of a method that is defined by the object’s type. Different types define different methods. Methods of different types may have the same name without causing ambiguity. (It is possible to define your own object types and methods, using classes, see Classes) The method append() shown in the example is defined for list objects; it adds a new element at the end of the list. In this example it is equivalent to result = result + [a], but more efficient.
result.append(a)
문장은 '리스트 객체 결과'의 메소드(method)를 실행시킨다. 메소드란 객체에 속한 함수이다. 그리고 그 이름은 obj.methodname 으로 작성된다. obj는 일종의 객체이며, obj.methodname 은 어쩌면 하나의 표현식이라고도 할 수 있겠다.result.append(a)
에서result
는 obj 이고.append()
는 메소드의 이름이다. 메소드의 이름은 객체의 형식에 따라 정해진다. (리스트에 사용되는 메소드들이 있고, 또다른 객체, 즉 데이터 형에 사용되는 메소드들이 있다.) 서로 다른 객체의 메소드들은 같은 이름을 가져도 아무 문제가 없다. (나 혼자만의 객체 타입과 메소드를 클래스를 이용해 지정할 수도 있다. Classes를 참고하라. 아직 링크 연결되지 않음) 예시에서 본append()
라는 메소드는 리스트 객체를 위한 것이다. 이 메소드는 새로운 요소를 리스트의 끝에 추가한다.result = result = [a]
와 같은 기능이다. 하지만.append()
메소드가 더 효율적이다.
참조
참조1
Actually, call by object reference would be a better description, since if a mutable object is passed, the caller will see any changes the callee makes to it (items inserted into a list).
객체 자료를 불러내는 것이 더 나을 수도 있다. 왜냐하면 가변객체가 전달되기 때문이다. 발신자는 수신자가 진행한 모든 변경사항(리스트에 삽입된 값들)을 볼 수 있다.