# 시퀀스-리스트, 문자열, 튜플
= [1, 7, 5]
l = "korea"
s = ("a", 1, True)
t # 인덱스 0, 1, -1를 사용하여 접근
1], s[-1], s[0] l[
(7, 'a', 'k')
Sequence
)파이썬에는 iterable
과 iterator
라는 개념이 많은 곳에서 사용된다. 그런데 파이썬을 처음 배우는 사람들에게 이런 추상적인 개념을 설명할 쉽게 설명할 자신이 없다. 이것을 알고 넘어가는 것이 무척 중요하다는 것은 알지만 그러하다.
그래서 추상적이지만 아주 추상적이지 않아서 어느 정도 구체적인 사례로 설명할 수 있는 sequence
라는 개념을 가지고 시작한다. 시퀀스는 순서가 있는 iterable이다. 그러니까 iterable
의 일종이고, 바꿔말하면 sequence
는 iterable
의 부분집합이다.
이제 우리가 다룰 시퀀스가 어떤 개념에 속하는지 정리해 보자. 우선 정의를 보자.
파이썬 용어집에 따르면 sequence의 정의는 다음과 같다.
__getitem__()
special method and defines a __len__()
method that returns the length of the sequence. Some built-in sequence types are list, str, tuple, and bytes. Note that dict also supports __getitem__()
and __len__()
, but is considered a mapping rather than a sequence because the lookups use arbitrary hashable keys rather than integers.sequence
보다 더 큰 집합인 iterable
은 다음과 같이 정의할 수 있다.
Iterable
: Any object that can be iterated over (e.g., lists, tuples, strings, dictionaries, sets).Sequence
는 Iterable
의 부분집합으로 그림 그림 8.1 같이 정리할 수 있다. Iterable
에는 sequence
와 non-sequence
로 나눌 수 있다.
iterable
에는 sequence
와 non-sequence
로 나눌 수 있는데, sequence
와 다른 mapping
과 set
이 있으며, 쓰임새가 다르다. 이것은 아래와 같이 정리할 수 있다.
list
, str
, tuple
이 대표적인 경우이다. - lis
t: mutable - tuple
: immutable - str
: immutable
키: 값
쌍으로 구성되어 있어서 어떤 값에 접근할 때 키(key)를 사용한다.
set
이 대표적인 예로 수학에서 사용되는 집합과 같은 개념으로, 중복된 값을 가질 수 없고, 서로 다른 값들(unique)로 구성된다. 집합에 사용되는 연산을 적용할 수 있다.
다음 코드는 시퀀스에 속하는 리스트(list), 문자열(str), 튜플(tuple)에서 인덱스(순서)를 사용하여 값을 꺼내오는 예이다.
# 시퀀스-리스트, 문자열, 튜플
= [1, 7, 5]
l = "korea"
s = ("a", 1, True)
t # 인덱스 0, 1, -1를 사용하여 접근
1], s[-1], s[0] l[
(7, 'a', 'k')
다음은 mapping
인 딕셔너리(dictionary)에서 키(key)를 사용하여 값을 꺼내오는 예이다.
# 매핑: dictionary
= {"a": 1, "b": 10, "c": print, "d": True}
d "a"], d["b"], d["c"], d["d"] d[
(1,
10,
<function print(*args, sep=' ', end='\n', file=None, flush=False)>,
True)
다음은 set
에서 값을 꺼내오는 예이다. set
은 중복된 값을 가질 수 없고, 서로 다른 값들로 구성된다.
# 셋: set
= {1, 3, 3, 5, 5, 8, 9}
s1 = set([1, 3, 3, 5, 5, 8, 9])
s2 s1, s2
({1, 3, 5, 8, 9}, {1, 3, 5, 8, 9})
다음과 같은 리터럴과 생성자 함수를 사용하여 iterable 객체를 만들 수 있다.
[]
, list()
()
, tuple()
{}
, dict()
{}
, set()
str()
빈 객체는 다음과 같이 만든다.
[]
또는 list()
{}
""
, ''
set()
"", set() [], {},
([], {}, '', set())
이런 빈 객체들은 불리언 맥락에서 False
로 평가된다.
bool([]), bool({}), bool(""), bool(set())
(False, False, False, False)
Sequence가 파이썬 언어에서의 위치를 파악했으니까, 이제 스퀀스로 범위를 좁혀서 시퀀스를 가지고 어떤 연산을 할 수 있는지 알아보자.
Sequence에 대해서 다음과 같은 연산이 가능하다. 이것들을 익히고 나면 개별 문자열, list, tuple 등과 같은 타입을 이해하고 다루는 것이 간단해진다. 그래서 이 연산들은 암기하여 숙지할 필요가 있다. 설령 처음에 암기하고 반복하면 나중 파이썬 공부가 훨씬 수월해질 것이다.
예를 들어 튜플 언팩킹(tuple unpacking) 방법이 있다. 이것은 튜플에 속하는 값들을 하나씩 가져오는 방법을 말한다.
= (1, 2, 3)
x, y, z print(x, y, z)
1 2 3
이렇게 튜플 언팩킹을 이해했는데, 또 공부하다 보니 리스트 언팩킹(tuple unpacking)이라는 것도 나온다. 비슷하다.
= [1, 2, 3]
x, y, z print(x, y, z)
1 2 3
또 공부하다 보니 iterable 언팩킹이라는 것도 나온다. 이건 더 일반화된 개념이다.
= range(1, 4)
x, y, z print(x, y, z)
1 2 3
이렇게 개별적으로 공부하는 것보다는 시퀀스/iterable은 모두 이런 연산을 지원한다고 이해하고 나서, 개별 데이터 타입에 대해 접근하는 것이 훨씬 쉽다는 생각이 들어 이 장을 정리한 것이다.
in
연산자Sequence는 여러 개의 item으로 구성된다. 어떤 객체가 해당 sequence에 포함되어 있는지 확인할 때는 in
연산자를 사용한다.
= [98, 78, 81, 63, 55]
s = tuple('abc')
t 78 in s, "a" in t
(True, True)
문자열 Sequence인 경우에는 문자열을 구성하는 서브 문자열이 포함되어 있는지를 체크할 수 있다.
= "우리나라 아름다운 대한민국"
my_country "대한민국" in my_country
True
obj[index]
문법으로 사용하여 위치 값을 가지고 값을 가지고 올 수 있다. 인덱스는 항상 0
으로 시작한다(zero-based index). 끝에서 시작하는 경우에는 -1
부터 시작한다.
= [98, 78, 81, 63, 55]
s 0], s[-2] s[
(98, 63)
= ('abc', 87, 65, "M", True)
t 0], t[-1] t[
('abc', True)
= "My name is John Does.\n"
intro print(intro)
0], intro[-1] intro[
My name is John Does.
('M', '\n')
슬라이싱은 obj[start:stop:step]
문법을 사용하여 일련의 값을 가지고 오거나 또는 그 위치에 새로은 슬라이스로 된 값을 넣을 수 있게 해준다.
start
는 inclusivestop
은 exclusivestart
, stop
, step
는 빈 상태로 둘 수 있는데, 빈 채로 두면 다음과 같은 의미를 가진다.
start
를 빼면, obj[:stop]
로 처음부터라는 의미stop
을 빼면, obj[start:]
로 끝까지는 의미step
을 빼면, ‘하나씩 차례대로’ 의미를 가진다.= list(range(1, 11))
my_list my_list
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
= list(range(1, 11))
my_list 2:5] my_list[
[3, 4, 5]
만약 start
와 stop
을 빼면, 모두를 의미하는 데, 주로 값을 복사하는 데 이용한다(shallow copy).
= list(range(1, 11))
my_list = my_list[:]
new_list new_list
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
여기서 show copy
와 deep copy
의 개념을 알고 가자.
# deep copy
= list(range(1, 11))
my_list = my_list # deep copy
new_list 0] = 100
new_list[print(my_list)
print(new_list)
[100, 2, 3, 4, 5, 6, 7, 8, 9, 10]
[100, 2, 3, 4, 5, 6, 7, 8, 9, 10]
다음은 shallow copy로 값만을 복사해서 새로운 객체를 만든다. 만들어진 객체는 원래의 객체와는 독립적으로 존재하기 때문에, 만들어진 객체의 값을 바꿔도 원래 객체는 변하지 않는다. list.copy()
메서드를 써도 되지만, 슬라이싱을 이용하는 경우도 많다.
# shallow copy: 값만 복사
= list(range(1, 11))
my_list = my_list.copy() # list.copy() 메서드로
new_list # new_list = my_list[:]도 같은 효과
0] = 100
new_list[print(my_list)
print(new_list)
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
[100, 2, 3, 4, 5, 6, 7, 8, 9, 10]
start
는 inclusive, stop
은 exlusive이기 때문에, 다음과 같은 방법으로 obj[:값]
, obj[값:]
문법을 사용하여 2개로 쪼갤 때 편리하다.
= list(range(1, 11))
my_list # 이것을 앞 3개와 나머지로 나누는 방법
= my_list[:3], my_list[3:]
head, others print(head)
print(others)
[1, 2, 3]
[4, 5, 6, 7, 8, 9, 10]
step
에 음의 정수를 사용할 수도 있다. 이런 경우에는 뒤에서 앞으로 이동한다. 따라서 이 기능을 활용하여 값을 거꾸로 뒤집을 때 편리하게 사용된다.
= list(range(1, 11))
my_list -1] my_list[::
[10, 9, 8, 7, 6, 5, 4, 3, 2, 1]
슬라이싱에 대하여 값을 할당하거나 del
문을 사용하여 값을 삭제할 수 있다. 값을 할당할 때는 슬라이싱 부분을 좌변에 놓는다.
= list(range(1, 11))
my_list my_list
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
이 my_list
객체의 처음 3개의 아이템의 값을 11, 22, 33으로 바꾸고자 하면 다음과 같이 할 수 있다.
3] = [11, 22, 33]
my_list[: my_list
[11, 22, 33, 4, 5, 6, 7, 8, 9, 10]
다음은 my_list
의 4, 5, 6 값을 삭제한다.
del my_list[3:6]
my_list
[11, 22, 33, 7, 8, 9, 10]
좌변과 우변의 개수가 달라도 된다. 그래도 해당 부분의 값이 바뀐다.
1:3] = [100]
my_list[ my_list
[11, 100, 7, 8, 9, 10]
단, =
우변에는 항상 iterable
이 와야 한다. 위 코드에서 my_list[1:3] = 100
라고 하면 오류가 발생한다.
1:3] = 100 my_list[
--------------------------------------------------------------------------- TypeError Traceback (most recent call last) Cell In[25], line 1 ----> 1 my_list[1:3] = 100 TypeError: must assign iterable to extended slice
슬라이싱 연산은 연산의 대상이 되는 데이터의 타입을 항상 유지시킨다.
= tuple(range(1, 11))
my_tuple 1:2] my_tuple[
(2,)
range(start, stop, step)
함수는 정수로 된 시퀀스를 만들 때 사용되는데, 슬라이싱과 유사한 문법을 가지고 있다. 또 그런데 이 함수는 값을 바로 만들지 않고, range
라는 객체를 반환하고, 이 객체를 활용하여 값을 만든다. 이렇게 하는 이유는 메모리 효율성을 높이기 위한 것으로, iterator라는 개념과 연결된다.
range(10) # 0에서 9까지
range(0, 10)
이것을 구체적인 값으로 바꿀 때 list()
함수를 많이 사용한다.
list(range(1, 10)) # 1부터 9까지, 리스트
[1, 2, 3, 4, 5, 6, 7, 8, 9]
tuple()
함수에 넣으면 튜플이 된다.
tuple(range(10, 0, -1))
(10, 9, 8, 7, 6, 5, 4, 3, 2, 1)
반면 for/in
루프는 내부에 각각의 값을 반환하는 장치가 마련되어 있다(iterator protocol). 따라서 range()
함수가 반환하는 것을 실제 값으로 구체화하지 않아도 바로 사용할 수 있다.
for i in range(5):
print(i)
0
1
2
3
4
zip()
함수는 여러 시퀀스에 있는 아이템들을 해당 위치에 있는 것끼리 모아서 튜플로 변환한 iterable을 만든다. range()
함수처럼 실제 값을 바로 반환하지 않는다. for
문 등과 같이 iterator protocol를 사용하여 계산에 사용된다.
= [1, 2, 3, 4]
list1 = ["a", "b", "c", "d"]
list2 zip(list1, list2)
<zip at 0x15d5ea240>
= [1, 2, 3, 4]
list1 = ["a", "b", "c", "d"]
list2 print(list(zip(list1, list2)))
print(tuple(zip(list1, list2)))
for item in zip(list1, list2):
print(item)
[(1, 'a'), (2, 'b'), (3, 'c'), (4, 'd')]
((1, 'a'), (2, 'b'), (3, 'c'), (4, 'd'))
(1, 'a')
(2, 'b')
(3, 'c')
(4, 'd')
enumerate()
함수는 시퀀스의 각 아이템에 인덱스를 부여해 준다. for/in
문은 인덱스 없이 그대로 값을 사용하는데, 그 위치값(index)이 필요한 경우에 사용한다.
= ["a", "b", "c", "d"]
my_list list(enumerate(my_list))
[(0, 'a'), (1, 'b'), (2, 'c'), (3, 'd')]
Sequence에 들어 있는 아이템의 개수는 len()
함수를 사용하여 구한다.
= [1, 7, 5, 6, 3]
l = "korea is"
s = ("a", 1, True, [1, 2, 3])
t len(l), len(s), len(t)
(5, 8, 4)
최솟값, 최댓값은 min()
, max()
함수를 사용하여 구한다.
= [1, 7, 5, 6, 3]
l min(l), max(l)
(1, 7)
print(max(1, 7, 5, 6, 3))
print(min(1, 7, 5, 6, 3))
7
1
sum()
함수는 합계를 계산하는 데, 이 함수에는 값들을 하나의 iterable로 주어야 한다.
sum(range(1, 101))
5050
어떤 값이 주어진 sequence의 항목에 존재하는지, 즉 그 membership을 확인할 때는 x in s
문법을 사용한다. 포함하지 않는지를 확인할 때는 not in
을 사용한다.
1 in list(range(5))
True
10 not in list(range(10))
True
시퀀스에 +
를 사용하면 두 객체가 결합되어 하나의 새로운 객체가 된다. s * n
을 사용하면 값들이 반복하여 만들어진다.
11, 22, 33] + [44, 55] [
[11, 22, 33, 44, 55]
"a", "b", "c") + ("d", "e") (
('a', 'b', 'c', 'd', 'e')
11, 22, 33] * 3 [
[11, 22, 33, 11, 22, 33, 11, 22, 33]
"a", "b", "c") * 3 (
('a', 'b', 'c', 'a', 'b', 'c', 'a', 'b', 'c')
시퀀스 등에서 값을 개별 변수들로 풀어 내는 방법이다. 좌변과 우변의 개수가 맞아야 한다. 이렇게 하는 것을 병렬 할당(parallel assignment)라고도 한다.
# list를 unpacking
= [1, 3, 5]
a, b, c print(a, b, c, sep=", ")
1, 3, 5
# tuple을 unpacking
= (1, 3, 4, 5)
a, b, c, d print(a, b, c, d, sep=", ")
1, 3, 4, 5
어떤 함수가 tuple을 반환하는 경우, 이와 같은 방법으로 값을 받아서 사용한다.
= divmod(19, 3)
q, r q, r
(6, 1)
만약 어떤 값들은 할당하고, 나머지들을 하나의 리스트로 묶을 수도 있다. 이 경우 리스트에 들어갈 것을 *
을 사용한다.
*d = range(1, 101)
a, b, c, print(a, b, c)
print(d)
1 2 3
[4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100]
*_, l3, l2, l1= range(1, 101)
f1, f2, f3, print(f1, f2, f3, l3, l2, l1)
1 2 3 98 99 100
_
도 하나의 변수이기는 한데, Python 사용자들은 앞으로 사용하지 않을 값을 담을 때 주로 사용한다.
range()
함수의 결과를 list()
나 tuple()
등과 같은 함수를 통해서 실제 값을 만들지 않아도 upacking이 되고 있다. 즉, 이 의미는 unpacking에도 for
문을 사용할 때 처럼 iterator protocol이 들어 있음을 의미한다.
Unpacking은 함수의 인자(argument)를 줄 때도 편리하게 사용된다.
def f(a, b, c):
return a + b + c
= (1, 2, 3)
k *k) f(
6
Unpacking은 for
문에서도 유용하게 사용된다. 이 구문도 암기해야 한다.
= [(1, "a"), (2, "b"), (3, "c")] # a list of tuples
my_list for n, c in my_list:
print(c + str(n))
a1
b2
c3
시퀀스에 포함된 아이템을 정렬하는 문제를 생각하자.
list.sort()
함수: list
는 mutable 객체이다. 이 메서드는 해당 리스트의 메모리에서(in-place) 포함된 아이템을 정렬한다. reverse=True
라는 인자를 사용하여 내림차순으로 정렬할 수 있다.
= [1, 3, 5, 2, 5, 7, 8, -1]
my_list print(id(my_list))
5852970304
my_list.sort() print(my_list)
print(id(my_list))
[-1, 1, 2, 3, 5, 5, 7, 8]
5852970304
=True)
my_list.sort(reverseprint(my_list)
print(id(my_list))
[8, 7, 5, 5, 3, 2, 1, -1]
5852970304
파이썬 내장 함수 sorted()
는 아무 sequence(iterable)에 대하여 사용할 수 있다. list.sort()
함수는 list
가 mutable 특성을 가진 점을 이용한다. 시퀀스에서는 tuple
처럼 immutable인 경우도 있기 때문에, mutability에 구애받지 않고 사용할 수 있게 하기 위해서 in-place
방식이 아닌 새로운 객체를 만드는 방식으로 작동하며, 결과는 list
로 반환한다. reverse
인자는 앞의 list.sort()
함수와 같다. 그러니까 sorted()
함수는 임의의 iterable을 받아서 정렬한 다음 그 결과를 list
로 반환한다.
= [1, 3, 5, 2, 5, 7, 8, -1]
my_list print(id(my_list))
5852945408
= sorted(my_list)
my_list print(my_list)
print(id(my_list))
[-1, 1, 2, 3, 5, 5, 7, 8]
5861569088
다음은 tuple
에 적용한 예이다.
= (1, 3, 5, 2, 5, 7, 8, -1)
my_tuple sorted(my_tuple)
[-1, 1, 2, 3, 5, 5, 7, 8]
sorted()
함수에 key=fn
이라는 키워드 인자를 사용하여 단순한 값이 아닌 함수 fn
의 결과로 만들어지는 값을 기준으로 정렬이 가능하다. 이 기능은 매우 강력하다.
= ['grape', 'raspberry', 'apple', 'banana']
fruits fruits
['grape', 'raspberry', 'apple', 'banana']
이 객체를 sorted()
함수에 넣으면 유니코드(Unicode) 코드 포인트 순서대로 정렬된다.
sorted(fruits)
['apple', 'banana', 'grape', 'raspberry']
fruits
리스트에 들어 있는 값들의 문자열 길이에 따라서 정렬하려면 다음과 같이 key
에 문자열의 길이를 구하는 len()
함수를 지정한다. 끝에 ()
가 없다. 함수가 실행된 값을 전달하는 것이 아니라 함수 자체를 전달한다.
sorted(fruits, key=len)
['grape', 'apple', 'banana', 'raspberry']
key=fn
에 전달할 수 있는 함수는 하나의 인자를 취해서 하나의 값을 반환하는 함수라면 다 괜찮다. 사용자 정의 함수도 넣을 수 있다.
다음 my_fn()
함수는 단어를 받아서 거꾸로 쓴 결과를 반환한다. 이 함수를 key
인자에 주었다.
def my_fn(word):
return word[::-1]
# 거꾸로 쓴 단어들
for word in fruits:
print(my_fn(word))
# 이 함수를 key에 넘김
sorted(fruits, key=my_fn)
eparg
yrrebpsar
elppa
ananab
['banana', 'apple', 'grape', 'raspberry']
복잡한 객체를 대상으로 정렬할 때 key
인자를 사용할 때 도움이 되는 함수가 operator
모듈에 존재한다.
operator.itemgetter()
함수는 아이템을 선택하는 기능을 제공한다. 다음 예를 보자. 다음 예는 리스트의 아이템이 딕셔너리 구조를 가지고 있는 students
객체가 있는데, 내부의 딕셔너리의 age
키를 기준으로 정렬하기 위해서 operator.itemgetter('age')
를 key
인자에 적용했다.
import operator
# 딕셔너리로 구성된 리스트
= [
students 'name': 'John', 'age': 25},
{'name': 'Jane', 'age': 22},
{'name': 'Dave', 'age': 24},
{
]
# age를 기준으로 정렬
= sorted(students, key=operator.itemgetter('age'))
sorted_students
sorted_students
[{'name': 'Jane', 'age': 22},
{'name': 'Dave', 'age': 24},
{'name': 'John', 'age': 25}]
다음은 아이템의 튜플인 경우이다. 튜플인 경우 키를 사용할 수 없기 때문에 operator.itemgetter(1)
와 같이 인덱스를 사용하여 정렬 기준을 잡았다.
import operator
= [
metro_data 'Tokyo', 'JP', 36.933, (35.689722, 139.691667)),
('Delhi NCR', 'IN', 21.935, (28.613889, 77.208889)),
('Mexico City', 'MX', 20.142, (19.433333, -99.133333)),
('New York-Newark', 'US', 20.104, (40.808611, -74.020386)),
('São Paulo', 'BR', 19.649, (-23.547778, -46.635833)),
(
]sorted(metro_data, key=operator.itemgetter(1))
[('São Paulo', 'BR', 19.649, (-23.547778, -46.635833)),
('Delhi NCR', 'IN', 21.935, (28.613889, 77.208889)),
('Tokyo', 'JP', 36.933, (35.689722, 139.691667)),
('Mexico City', 'MX', 20.142, (19.433333, -99.133333)),
('New York-Newark', 'US', 20.104, (40.808611, -74.020386))]
operator.itemgetter()
와 비슷한 함수로 operator.attrgetter()
가 있다. 이 함수는 어떤 객체의 인스턴스를 attribute 값을 가지고 정렬할 때 사용된다.
import operator
# 클래스
class Student:
def __init__(self, name, age):
self.name = name
self.age = age
def __repr__(self):
return f'Student(name={self.name}, age={self.age})'
# 인스턴스
= [
students 'John', 25),
Student('Jane', 22),
Student('Dave', 24),
Student(
]
sorted(students, key=operator.attrgetter('age'))
[Student(name=Jane, age=22),
Student(name=Dave, age=24),
Student(name=John, age=25)]
이와 같이 sorted()
내장 함수는 리스트 뿐만 아니라 임의의 iterable를 받을 수 있고, key
인자를 사용하여 다양한 상황에서 정렬과 관련된 다양한 기능을 수행할 수 있는 다재다능한 도구이다.
[x를사용계산코드 for x in s]
문법을 사용하여 새로운 리스트를 만드는 방법이다. x
는 s
의 아이템을 하나씩 가지고 온다.
**2 for n in range(1, 11)] [n
[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
List comprehension은 리스트를 만든 데 사용되는데, 비슷한 방법으로 딕셔너리, 셋도 만들 수 있다. 좀 더 일반화된 generator expression을 만들 수 있다. 따라서, 반드시 알아야 하는 문법이다.
다음은 코드를 보자.
for i, c in enumerate("abcd")} {c: i
{'a': 0, 'b': 1, 'c': 2, 'd': 3}
"abcd"
는 문자열로, sequence의 하나이다.enumerate()
함수는 각 아이템에 인덱스를 붙여 준다. 이 함수를 호출하여 iterable을 반환한다.for
문 안에서 unpacking을 적용하여 인덱스, 문자 쌍으로 나눈다.리스트 컴프리헨션은 리스트를 만드는 문법인데, 비슷한 문법을 일반적인 경우로 확장한 것이 generator expression이다. ()
안에 리스트 컴프리헨션의 문법과 같이 코딩한다.
이와 같은 방법을 사용하는 이유는 리스트와 같이 실제 값을 만들어 사용하는 것보다 메모리 효율성이 높아진다. 왜냐하면 generator object
는 필요한 값들을 하나씩 만들기 때문이다.
# 1에서 19까지 숫자들을 제곱하는 generator expression
= (n**2 for n in range(1, 11))
squares_generator squares_generator
<generator object <genexpr> at 0x15cb012f0>
Generator expression은 generator object
를 만든다. 이 객체는 iterator protocol을 갖추고 있다.
for n in squares_generator:
print(n)
1
4
9
16
25
36
49
64
81
100
list((n**2 for n in range(1, 11)))
[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
sum((n**2 for n in range(1, 11)))
385
이와 같이 함수 ()
안에 generator expression
이 단독 인자로 사용되는 경우는 ()
를 생략할 수 있다.
list(n**2 for n in range(1, 11))
[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
sum(n**2 for n in range(1, 11))
385
이 장에서는 (str, list, tuple 등을 포함하는) 파이썬 시퀀스의 개념과 시퀀스를 가지고 할 수 있는 연산을 정리하였다.