이 문서는 가리사니 개발자 포럼에 올렸던 글의 백업 파일입니다. 오래된 문서가 많아 현재 상황과 맞지 않을 수 있습니다.
이글의 출처는 다음과 같습니다. [허가됨] http://blog.naver.com/PostView.nhn?blogId=bulletlib&logNo=220608533258&redirect=Dlog
Intro.
파이썬 전체를 훑어보는 챕터이다. 파이썬에 대한 깊이 있는 정리는 책, 문서, 개발 과정으로부터 얻은 정보 등을 통해서 천천히 추가할 예정이다.
여기서는 기본적인 변수와 식, 내장 자료형, 제어문, 함수, 람다, 생성기, 코루틴, 데코레이터, 클래스와 객체, 예외처리, 모듈, 파일 입출력에 대해 다룬다.
글을 쓰는 나를 위한 것이므로 친절하지 않을 수도 있다.
이 챕터는 프로그래밍에 대한 경험이 있는 사람이나 똑똑한 사람이 파이썬을 순식간에 훑기 쉬운 퀵 레퍼런스의 역할을 할 것이라고 생각한다.
1. 변수와 식
파이썬은 ‘Dynamic typing’을 사용한다. 따라서 변수에 자료형을 지정하지 않는다. 저장하는 값에 따라 ‘type’이 결정된다. 식별자를 선언하고 값을 넣기만 하면 된다.
식 또한 간단하다. 식은 연산자, 변수, 상수, 값, 함수로 구성된 문장이며, 인터프리터나 컴파일러가 해석하고 계산해서 다른 값을 생산한다. 수학의 식은 수로 한정되지만, 프로그래밍에서는 진위값, 문자열도 포함된다.
다음은 사면체수를 표현하는 파이썬 코드이다. 물론 수학식을 이용한 더 간단한 표현도 가능하지만, 함수까지 어우르는 모습과 사용 방법을 보여주기 위해 다음과 같이 작성하였다.
def tetrahedral(n):
ret = 0;
while n > 0:
ret += reduce(lambda x, y: x + y, range(1, n + 1))
n -= 1;
return ret
print tetrahedral(110) 파이썬은 모든 것이 객체이다. C-like 언어들에서 ret = 0은 어느 특정 주소에 0이라는 값이 담기는 것을 의미한다. 물론 파이썬에서도 언어적 측면만 두고 보았을 때는 ret = 0은 ret에 0이 담겨있다고 봐도 무방하다. 그러나 파이썬은 내부적으로 0이라는 값을 지닌 객체를 ret이라는 식별자와 바인딩하고 있는 형태이다.
위에서 언급한 바와 같이 프로그래밍에서의 ‘식(expression)’은 수 이외의 것도 리턴한다. 그 것은 while문의 조건인 n > 0을 보면 알 수 있다. C에서는 n > 0이 수를 반환하지만, 파이썬에서는 불리언 값인 True나 False를 반환한다.
파이썬은 다른 언어와 달리, 파이썬은 들여쓰기 깊이로 블록을 구분한다. while문을 살펴보면 while문 보다 들여쓰기를 더 깊게한 두 줄이 보일 것이다. 이 두 줄이 while문의 블록인 것이다.
그리고 적절한 연산 후, 값을 return하는 모습을 살펴볼 수 있다. (함수)
def로 선언된 함수의 본체 뒤에는 print 하는 코드가 등장한다. Python2에서는 print는 ‘문(statement)’이다. (참고로 Python3에서는 print가 함수이다.) 파이썬도 print에 format을 주어서 출력이 가능하지만 이는 여기서는 생략하도록 한다.
2. 내장 자료형
정수형, 실수형과 같은 기본적인 자료형은 생략한다.
ⓐ 문자열(시퀀스)
문자열은 작은 따옴표, 큰 따옴표, 삼중 따옴표로 둘러 싸서 만든다. 삼중 따옴표는 특별한데, 끝 부분의 삼중 따옴표가 오기 전까지 여러 줄에 걸쳐서 텍스트를 담을 수 있다. 문자열도 시퀀스이므로 0부터 인덱스된다.
str1 = 'I love you.'
str2 = "I loved you."
str3 = """Lorem ipsum dolor sit amet, consectetur adipiscing elit.
Quisque egestas egestas turpis, non laoreet orci ultrices eu.
Aliquam at ante rutrum, tincidunt augue sed, facilisis ligula.
Quisque tempus placerat mauris, sit amet dapibus lorem sagittis ut.
Vivamus suscipit dolor id felis porttitor laoreet.
Integer iaculis fringilla justo. Sed vitae dui lorem.
Pellentesque in egestas ex. In hac habitasse platea dictumst.
Cras ullamcorper eleifend imperdiet. Sed faucibus est justo, quis sagittis mi scelerisque vitae.
Mauris nec enim lacinia, tempor tortor at, facilisis ex."""
ⓑ 리스트(시퀀스)
리스트는 임의의 객체의 시퀀스이다. 객체를 담을 수 있으므로 컨테이너라고 부르기도 한다. 리스트는 대괄호로 둘러싸서 생성한다.
zoo = ['pooh', 'tiger', 'monkey']
리스트도 또한 0부터 인덱스된다.
객체를 담는 리스트 또한 객체이다. 따라서 자신만의 메소드를 가질 수 있다.
zoo.append('Panda')
리스트의 끝에 새로운 항목을 추가한다. 인덱스를 이용한 삽입도 가능하다.
zoo.insert(1, 'Panda')
해당 자리에 있던 항목은 뒤로 밀려나게된다.
식별자에게 타입을 부여하기 위해 빈 리스트를 생성하는 방법은 다음과 같다.
zoo = []
zoo = list()
C-like 언어들의 다차원 배열처럼 사용할 수도 있다. 하지만 이는 생략하도록 한다.
다음과 같이 파일을 읽어서 값을 리스트에 저장할 수도 있다.
f = open("list.dat")
dat = f.readlines()
f.close()
val_list = [float(x) for x in dat]
print val_list
ⓒ 튜플(시퀀스)
튜플도 리스트와 유사한 컨테이너이다. 단, 리스트는 가변적이지만 튜플은 그렇지 않다. 즉, 새로운 항목을 추가할 수 없다. 튜플은 괄호로 둘러 싸서 생성할 수 있다.
튜플은 immutable객체이기 때문에 저장되는 공간만큼만 메모리에 할당된다. 반면, 리스트는 삽입 속도를 높이기 위해 리스트를 원래 크기보다 더 크게 할당해둔다. 따라서 메모리의 낭비를 줄이고 싶다면 튜플을 사용하는 것이 바람직하다.
예제는 다음과 같다.
t = (1, "John")
num, name = t
ⓓ 사전
key로 인덱스되는 객체들을 담는 컨테이너이다. 순서 구분이 필요 없는 데이터를 빠르게 검색하기 위한 용도로 사용된다. 내부적으로는 해시 테이블이며 중괄호를 이용해서 생성한다.
product_info = {
"name" : "french onion soup",
"price" : 15000,
"url" : "~/french_onion_soul"
}
사전에 접근하기 위해서는 키를 사용하면 된다.
print product_info["name"]
추가/수정 역시 키를 기반으로 한다.
product_info["price"] = 17000
product_info["country"] = "France"
참고로 키는 immutable 객체만 가능하다. 리스트, 사전과 같은 것들은 내용이 변할 수 있으므로 불가능하다.
빈 사전은 다음과 같이 생성이 가능하다.
product_info = {}
product_info = dict()
키 리스트는 다음과 같이 추출할 수 있다.
l = list(product_info)
키 삭제는 del문을 이용하면 된다.
del product_info["price"]
ⓔ 집합
집합 역시 순서 없는 어떤 모음을 저장하는 컨테이너이다. 수학에서의 집합의 특성을 그대로 가지고 있는데, 중복되는 요소가 존재하지않는다. 그리고 또한, 숫자로 색인이 불가능하다. 하지만 add(단일), update(여러개)를 이용해서 요소를 추가할 수 있고, remove로 제거가 가능하다.
str1 = "Hello python"
s = set(str1)
set([' ', 'e', 'H', 'l', 'o', 'n', 'p', 't', 'h', 'y'])
수학에서의 연산인 교집합, 합집합, 차집합, 대칭 차집합과 같은 집합 연산을 제공한다. 수학에서 집합의 연산 결과가 또 다른 집합인것과 같이, 여기서도 집합 연산의 결과의 타입은 집합이다.
str1 = "Hello python"
str2 = "Hello World!"
a = set(str1)
b = set(str2)
print a & b # 교집합
print a | b # 합집합
print a - b # 차집합
print a ^ b # 대칭 차집합
3. 조건문
파이썬에서는 if, else문이 조건문의 전부이다. 다른 언어의 조건문과 같이 조건에 따라 블록이 선택적으로 실행되는 구조이다. 조건문에서 올 수 있는 조건은 불리언 값을 리턴하는 어떠한 값, 식, 문이라도 모두 가능하다.
if a < b:
print "It's true."
else:
print "It's false."
다음과 같이 간단하게 쓸 수 있다. 빈 블록을 두고 싶다면 pass 문을 사용하면 된다.
if a < b:
print "It's true."
else:
pass
파이썬은 or, and, is, not이라는 키워드를 지원하여 유연하고 직관적으로 코드를 구성할 수 있다.
a = 2
b = 10
if a is not 2 and b is 10:
print "It's true!"
'만약 a가 2가 아니고 b가 10이라면'과 같이 읽을 수 있다.
마치 영어를 읽는 기분이다.
파이썬은 switch-case 문이 없으므로 여러 조건 검사에는 다음과 같이 elif 문을 사용한다.
grade = 'a'
if grade is 'a':
print "You got the grade A."
elif grade is 'b':
print "You got the grade B."
elif grade is 'c':
print "You got the grade C."
elif grade is 'd':
print "You got the grade D."
else:
print "F...?"
이외에도 파이썬은 C-like 언어들의 배열 역할을 하는 리스트를 포함한 시퀀스에 대해 in 연산자(membership test)를 지원한다. in 연산자는 시퀀스 내에 값의 존재 여부에 따라 진위 값을 반환한다. 여기서 시퀀스는 문자열, 리스트, 튜플 등이 존재한다.
color = ['Red', 'Blue', 'Green', 'Magenta', 'Yellow']
selected = 'Blue'
flag = True
if selected in color:
flag = True
else:
flag = False
flag = True를 해주는 이유는 식별자만 존재하면 타입이 결정되지 않기 때문이다. 선택한 값이 컬러 목록에 있으면 플래그를 설정한다. in 연산자로 인해 다음과 같이 코드를 줄일 수 있다.
color = ['Red', 'Blue', 'Green', 'Magenta', 'Yellow']
selected = 'Blue'
flag = True
flag = selected in color
아름답다.
4. 반복문
파이썬에는 for와 while 반복문이 존재한다. 이 역시 불리언 값에 따라 블록의 반복 여부가 결정된다. 기본적인 반복은 다음과 같다.
n = 10
while n > 0:
print "Countdown: " + str(n)
n -= 1
10부터 카운트다운하는 코드이다. 다른 언어의 while과 차이점은 없다.
파이썬의 for문은 특별하다. 용법 위주로 간단한 설명만 하겠다.
l = [1,2,3,4,5]
for n in l:
print n
위의 코드와 동일한 표현으로 다음 코드도 가능하다.
for n in range(1,6):
print n
range는 리스트를 생성하는 함수이다. range(x) # 0 ≤ n < x range(x, y) # x ≤ n < y range(0, 12, 3) # 3은 stride이다. [0, 3, 6, 9] range(5, 0, -1) # [5, 4, 3, 2, 1] for의 기본적인 구조는 다음과 같다.
for 변수 in 시퀀스(혹은 파일):
text = open("lorem.txt")
for line in text:
print line
5. 함수
함수는 def문을 사용해서 생성한다. 참고로 함수의 바디 또한 객체이기 때문에 함수의 이름과 바디가 바인딩되는 것이라고 생각하면 된다.
C-like 함수와 달리 함수의 선언시에 사용된 이름만 알고 있다면 인자를 넘기는 순서는 지키지 않아도 상관없다. 또한 디폴트 인자가 존재하는 경우 생략해도 상관없다.
def adder(x, y, z=100):
print x
print y
print z
return x + y + z
print adder(y=30, z=10, x=20)
print adder(x=300, y=200)
C-like 언어에서 전역 변수에 접근할 때 그냥 사용하기만 하면 됬었다. 파이썬에서는 global 문을 붙여주어야한다.
x = 0
def adder():
global x
x += 10
print x
adder()
print x
함수 내부에서 전역 변수를 global 문을 붙여서 사용하겠다고 명시해야한다.
6. 람다
람다는 람다 대수에서 유래된 함수이다. 물론 논리학에도 람다가 존재하며 맥락은 같다고 생각한다.
람다를 사용하는 이유를 정리하면 다음과 같다.
- 다른 함수에게 값 뿐만 아니라 작동 방식도 전달할 수 있다. (함수형 프로그래밍)
- 재사용하지 않는 일회성 코드에 사용할 수 있다. (C-like의 인라인 함수, 매크로 함수)
람다도 이름만 존재하지 않을 뿐 이름을 붙여줄 수도 있다.
f = lambda x: x**x
print f(5)
작동 방식을 전달하는 예제는 다음과 같다.
def key(x):
return x[0]
a = [(1, 2), (3, 1), (5, 10), (11, -3)]
a.sort(key=key)
print a
튜플의 인덱스 0의 순서대로 정렬하는 코드이다. 람다를 이용하면 다음과 같이 줄일 수 있다.
a = [(1, 2), (3, 1), (5, 10), (11, -3)]
a.sort(key=lambda x: x[0])
print a
작동 방식을 지정해주어서 더 깔끔해질뿐만 아니라 직관성도 따라온다. 세 제곱수가 큰 순서대로 정렬하면 다음과 같다.
a = [ -1, -8, 3, -4, 2, 5, -7]
a.sort(key=lambda x : x*3, reverse=True)
print a
다음과 같이 멋진 코드도 가능하다.
from random import randint
l = [randint(1,100) for n in range(1, 11)] # random list
print l
q=lambda s:s if len(s)<2 else q([x for x in s[1:]if x<s[0]])+[s[0]]+q([x for x in s[1:]if x>=s[0]])
print q(l)
람다를 인자로 받고 싶다면 다음과 같이 가능하다.
def dummy(f):
return f(30)
print dummy(lambda x: x*2)
7. 이터레이터 제너레이터
ⓐ 이터레이터
iterable 객체를 관리해주는 객체가 iterator이다. traverse가 가능한 객체의 요소를 순서대로 접근 가능하며 for문이 iterator안의 next()(next() in Python3)을 실행한다. next 메소드는 현재 가리키고 있는 값을 반환하고 그 다음 객체를 가리킨다.
이터레이터는 next 함수나 next 메소드를 사용해서 실행시킬 수 있다.
str = 'asfl'
it = iter(str)
print it.next()
print it.next()
print next(it)
print it.next()
print next(it)
모두 반환하고 나서 next를 호출하면 StopIteration 예외가 발생한다.
ⓑ 제너레이터
제너레이터는 yield를 사용하는 함수로, 이터레이터를 간단하게 만들 수 있다. 제너레이터에서 사용한 yield는 return과 동일하다. 한 가지 차이점이 있다면 리턴을 하고 그 라인에서 멈추고, 다음 next()가 호출될 때 코드가 yield까지 다시 실행된다.
다음은 카운트 다운하는 제너레이터다.
def countdown(n):
print "Count down..."
while n > 0:
yield n
n -= 1
c = countdown(3)
print type(countdown)
print type(c)
참고로 countdown은 함수지만, c는 제너레이터 객체임을 알 수 있다. 이제 다음과 같이 코드를 추가해보자.
print c.next()
print c.next()
print c.next()
하지만 next를 직접하는 것보다 for문을 사용하는 것이 일반적이다. 앞에서도 말했지만 for문은 next를 실행시킨다. 따라서 다음과 같이 코드를 바꿔볼 수 있다.
for n in countdown(3):
print n
8. 코루틴(Coroutine)
코루틴은 일반적인 서브루틴의 개념과 다르다. 코루틴은 여러개의 엔트리 포인트가 존재할 수 있으며 돌아갈 위치를 지정할 수 있다. 서브루틴이 엔트리가 하나라는 점과 리턴 시 호출자에게 돌아간다는 점과 대비된다.
이는 모든 루틴이 서로 동등한 관계로 서로를 호출할 수 있다는 것을 의미하며, 동시성을 갖는다. 이러한 특징을 이용해서 게임에서 오브젝트 간 상호작용을 표현하는데 사용되곤한다.
단, 파이썬의 코루틴은 제너레이터를 이용한 논리적인 동시성일 뿐, 실제로는 동시가 아니다. 이는 파이썬의 구조의 한계 때문이다.
어쨋든 파이썬에서도 코루틴이라는 개념을 사용할 수 있다.
여기서도 yield를 사용하는데, 차이점이 있다면 코루틴에서는 리턴이 아니라 입력을 받는다. 제너레이터에서 yield를 만나면 반환하고 멈추는 역할을 했었다. 코루틴에서도 멈춘다는 사실은 동일하지만, 반환하지 않고 입력을 받는다.
코루틴에 대한 간단한 코드는 다음과 같다.
import sys
def recvr():
print "[+] Ready to recv"
while True:
n = (yield)
print "[!] Recved string: %s" % n
if n == "stop":
print "[-] Bye bye"
sys.exit()
coroutine = recvr()
coroutine.next()
coroutine.send("Hi")
coroutine.send("Hello")
coroutine.send("stop")
next()를 한 번 호출해준 이유는 yield가 있는 행 까지 실행시키기 위함이다.
제너레이터와 코루틴의 차이를 정리하자면 다음과 같다.
- 제너레이터는 데이터를 생산한다. (줌)
- 코루틴은 데이터를 소비한다. (받음)
9. 클로저, 데코레이터
ⓐ 클로저(Closure)
함수 내에서 또 다른 함수가 정의된 함수를 Nested Function이라고 한다. 보통 C-like 언어에서는 이런 것이 불가능하다.
def func(msg):
def inner_func():
print "Message: %s" % msg
return inner_func
output = func("Nested Function a.k.a Closure")
output()
함수는 6행에서 이미 실행되고 종료되었지만 인자로 전달한 값을 기억하고 출력하는 모습을 확인할 수 있다. 이러한 중첩 함수를 클로저라고 부른다.
내부에 있는 함수(inner_func)는 외부의 함수(func)가 네임스페이스에서 소멸되어도 존재한다.
ⓑ 데코레이터
데코레이터는 객체지향 디자인 패턴의 데코레이터 패턴과 동일하다. 기존의 함수에 추가적인 기능을 덧붙여서 사용할 수 있다.
단어 그대로의 데코레이터이다.
데코레이터의 대상이 되는 것은 function/instance method 모두 가능하다.
일단 간단한 문자열을 출력하는 origin 함수를 정의해보자.
def origin():
print "Decorator Example!"
멍청한 함수이다. 이제 함수의실행 시간을 측정하는 함수 timer를 만들어 볼 것이다.
from time import time
def origin():
print "Decorator Example!"
def timer():
s = time()
origin()
e = time()
print e - s
timer()
무의미한 짓이긴 하지만… 일단 시간을 측정했다. 데코레이터를 사용하기 위해 타이머 함수를 클로저로 변경할 것이다.
from time import time
def timer(f):
def wrapper():
s = time()
f()
e = time()
print "time:", e - s
return wrapper
@timer
def origin():
print "Decorator Example!"
origin()
아주 간단하다. 이 코드를 이해하고 싶다면 데코레이터 없이 함수를 데코레이터 패턴처럼 사용해보면 된다. 데코레이터는 생각보다 자주 등장하니깐 잘 익혀두자.
10. 클래스와 객체
파이썬에서 다루는 모든 값은 객체이다. 객체는 자신의 멤버와 메소드로 구성이 되어 있다. 객체를 만들기 위해서는 클래스 선언부터 해야한다. 파이썬의 dir 함수를 사용하면 객체의 메소드 정보를 볼 수 있다.
print dir(list)
['__add__', '__class__', '__contains__', '__delattr__', '__delitem__', '__delslice__', '__doc__', '__eq__', '__format__',
'__ge__', '__getattribute__', '__getitem__', '__getslice__', '__gt__', '__hash__', '__iadd__', '__imul__', '__init__',
'__iter__', '__le__', '__len__', '__lt__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__',
'__repr__', '__reversed__', '__rmul__', '__setattr__', '__setitem__', '__setslice__', '__sizeof__', '__str__',
'__subclasshook__', 'append', 'count', 'extend', 'index', 'insert', 'pop', 'remove', 'reverse', 'sort']
리스트도 또한 객체이기 때문에 위와 같이 많은 메소드를 제공한다. 파이썬의 클래스 선언은 매우 간단하다.
from copy import deepcopy
class stack(object):
def __init__(self): # Constructor
self.item = []
def push(self, object):
self.item.append(object)
def pop(self):
if self.item == []:
return None
else:
return self.item.pop()
def len(self):
return len(self.item)
def get_item(self):
return self.item
s = stack()
s.push("Apple")
s.push(10)
s.push({"key1" : "wow", "key2" : "cool"})
l = deepcopy(s.get_item())
print s.pop()
print s.pop()
print s.pop()
print s.pop()
print l
11. 예외처리
프로그램의 비정상적 종료 원인에는 버그와 예외가 존재한다. 하지만 버그는 보통 개발자의 실수를 의미하는 것이고, 예외는 개발자가 손쓸 방법이 없는 것들을 의미한다. 가령 네트워크의 문제로 수신 받던 데이터가 끊긴다던지, 파일을 개방했는데 IO에 문제가 생겼다던지 하는 문제들은 개발자가 다룰 수 없는 상황이다.
이러한 상황에 직면한 프로그램은 종료된다. 그리고 이렇게 종료되는 프로그램을 온전하다고 할 수 없다.
따라서 이렇게 발생 가능성이 있는 상황에 대해 예외 처리를 할 수 있다.
l = [1, 2, 3]
n = len(l) + 2
while n > 0:
try:
print l.pop()
except IndexError as e:
print e
n -= 1
try로 예외 가능성이 있는 코드를 실행시키고 except로 예외를 잡아서 핸들링한다. 간단한 코드라면 저렇게 예외 내용만 출력할 수 있고 원한다면 따로 핸들러를 두어서 적당한 처리를 맡길 수 있다.
파이썬 예외의 종류는 무수히 많으며 외울 필요는 없다. 프로그램이 터질 때 토해낸 메시지를 주어담아서 예외 처리 코드를 넣으면 된다. (무식터짐)
https://docs.python.org/2/library/exceptions.html
12. 모듈
C-like 언어로 따지면 헤더파일 정도 되겠다. 물론 C에는 네임스페이스 개념이 희미한 편이고, C++은 구체적이다. 뭐 아무튼 익숙한 개념이라고 생각한다. 위에서 무심하게 사용했던 import는 새로운 네임스페이스를 생성하고 임포트한 코드(*.py)를 모두 생성한 네임스페이스 안에서 실행시킨다. 가령 다음과 같은 경우를 생각해보자.
import math
print math.pi
math라는 네임스페이스에 있는 pi에 접근한다. 네임스페이스 이름을 붙여주고 싶다면 as 한정자를 사용하면된다. 한정자는 한씨성을 가진 할머니 이름이 아니라 용어이다.
import math as hanjeongja
print hanjeongja.pi
위의 내용을 현재 네임스페이스에 가지고 오고 싶다면 from 문을 사용한다.
from math import pi
print pi
임포트한 모듈의 내용은 dir 함수를 통해서 볼 수 있다.
import math
print dir(math)
파이썬에는 자신이 생각하는 내용은 보통 구현되어 있고 이렇게 모듈로 제공한다. 모듈을 찾아서 아이디어를 빠르게 구현하는데 아주 적합한 언어인 이유가 바로 이런 점이다.
13. 파일 입출력
앞에서는 줄 단위, 전체 라인 읽는 방법을 보여주었다. 이번에는 바이트 단위로 읽는 방법이다. 간단하다.
f = open("lorem.txt")
unit = 16
byte = f.read(unit)
while byte != "":
print byte
byte = f.read(unit)
f.close()
14. 함수형 프로그래밍
파이썬은 멀티 패러다임 언어답게 함수형 프로그래밍도 지원한다. 앞에서 정리한 람다와 파이썬이 제공하는 강력한 고차원 함수를 이용해 함수형 프로그래밍도 가능하다. 여기서는 map, reduce, filter를 소개한다.
ⓐ map
map 함수는 다음과 같은 시그니처를 가지고 있다.
map(func, list)
리스트의 멤버를 하나씩 꺼내서 함수에게 넘겨주고, 그 결과를 새로운 리스트에 담아서 반환하는 함수이다.
l = range(1, 11)
m = map(lambda x: x**2, l)
print l
print m
출력 결과는 다음과 같다.
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
매우 간결하게 코드를 표현할 수 있다. 다음은 map을 구현한 코드이다.
def my_map(f, l):
ret = []
for x in l:
ret.append(f(x))
return ret
ⓑ reduce
reduce 함수는 다음과 같은 시그니처를 가지고 있다.
reduce(func, sequence, init=None)
시퀀스라면 모두 가능하다. reduce는 결과를 누적해서 함수에 적용시킨다. 초기값이 존재한다면 초기값도 함께 누적시킨다.
print reduce(lambda x, y: x + y, [1,2,3,4,5])
결과는 15가 등장한다. 1과 2를 더한 3을, 뒤의 3과 더하고, 결과인 6을 4와 더하고, 결과인 10을 5와 더한 것이다. 조금 더 정확한 이해를 원한다면 다음 코드도 이해해야한다.
print reduce(lambda x, y: y + x, 'abcde')
결과는 ‘edcba’이다. 문자열에서 연산자 +는 concatenation이다. 이해가 안되면 다음 reduce를 구현한 코드를 살펴보자.
def my_reduce(f, seq, init=None):
l = list(seq)
if init is None:
ret = l.pop(0)
else:
ret = init
for x in l:
ret = f(ret, x)
return ret
ⓒ filter
필터는 이름에서도 와닿는다. 필터인 함수를 리스트의 멤버가 통과해서 자격이 있는 멤버만 새로 리스트로 생성된다.
filter(func, list)
사용해보자.
l = range(1,11)
m = filter(lambda x: x > 5, l)
print l
print m
결과: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] [6, 7, 8, 9, 10] 어려운 내용은 없다. filter를 구현한 코드는 다음과 같다.
def my_filter(f, l):
ret = []
for x in l:
if f(x): ret.append(x)
return ret