파이썬 리스트와 리스트 컴프리헨션

파이썬 리스트 메서드와 리스트 컴프리헨션

파이썬 리스트 메서드

 

append

리스트 자료형의 끝에 항목을 추가합니다. blog 리스트 자료형의 객체가 있을 때 blog [len(blog) : ] = [항목 값]와 같은 기능을 수행합니다.

 

>>> blog =[]
>>> blog.append("Captain")
>>> blog
['Captain']
>>> blog.append("BIN")
>>> blog
['Captain', 'BIN']
>>> blog[len(blog):]=["Captin BIN"]
>>> blog
['Captain', 'BIN', 'Captin BIN']

 

clear

리스트의 모든 항목을 삭제합니다. blog 리스트 자료형의 객체가 있을 때 del blog [:]와 같은 기능을 수행합니다.

 

# clear
>>> blog = ["Captain", "BIN"]
>>> blog
['Captain', 'BIN']
>>>
>>> blog.clear()
>>> blog
[]

# del
>>> blog = ["Captain", "BIN"]
>>> blog
['Captain', 'BIN']
>>>
>>> del blog[:]
>>> blog
[]

 

copy

리스트의 얕은 복사를 진행합니다. 참고로 얕은 복사 진행 시 인지하지 못한 문제가 발생할 수 있으며 자세한 내용은 이전 포스트 "파이썬 네임스페이스와 얕은 복사 vs 깊은 복사"에서 좀 더 자세한 내용을 확인할 수 있습니다.

# 리트스 얕은 복사
>>> list_1 = ["Captain",["BIN", "BLOG"]]
>>> list_2 = list_1.copy()
>>> list_3 = list_1
>>>
>>> list_1
['Captain', ['BIN', 'BLOG']]
>>> list_2
['Captain', ['BIN', 'BLOG']]
>>> list_3
['Captain', ['BIN', 'BLOG']]

# 리스트 객체 id값 확인
>>> id(list_1)
55096144
>>> id(list_2)
55097064
>>> id(list_3)
55096144

# 리스트 원소 변경
>>> list_2[1][0] = "America"

# 각각의 리스트 객체 값 확인
>>> list_1
['Captain', ['America', 'BLOG']]
>>> list_2
['Captain', ['America', 'BLOG']]
>>> list_3
['Captain', ['America', 'BLOG']]

 

count

얼핏 메서드 명만 보면 리스트 원소 개수를 반환하는 메서드처럼 보입니다. 그래서 아무 인자도 주지 않고 코드를 수행해 보면 "TypeError: count() takes exactly one argument (0 given)"와 같이 타입 에러가 발생합니다. 이 카운트 메서드는 인자로 전달하는 값의 개수를 반환하는 메서드입니다. 참고로 값을 카운트하는데 일차원 리스트를 기준으로 카운트합니다. 

 

>>> list_var = [0,1,2,3,[4,5],[4,5],2,3,3]
>>> list_var.count(0)
1
>>> list_var.count(7)
0
>>> list_var.count(4)
0
>>> list_var.count([4,5])
2
>>> list_var.count(1)
1
>>> list_var.count(2)
2
>>> list_var.count(3)
3

 

extend

리스트에 여러 개의 원소를 추가하여 리스트를 확장시킬 때 사용하는 메서드입니다.

 

>>> list_var = [0, 1, 2]
>>> list_var_1 = [3, 4, 5]
>>>
>>> list_var.extend(list_var_1)
>>> list_var
[0, 1, 2, 3, 4, 5]
>>>
>>> list_var.extend([6, 7, 8, 9])
>>>
>>> list_var
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

 

index

index 메서드는 index(value [, start [, end]])처럼 입력받는 값을 지정하고 선택 사항으로 시작과 끝을 지정해 줄 수 있습니다. 입력한 value의 값에 해당하는 인덱스를 반환합니다. 만약 해당하는 값이 없으면 "ValueError"가 발생합니다.

 

>>> list_var = [0, 1, 2, 1, 2, 3]
>>> list_var.index(2)
2
>>> list_var.index(2,3)
4
>>> list_var.index(2,3,5)
4
>>> list_var.index(3)
5
>>> list_var.index(3,0,4)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: 3 is not in list

 

insert

insert 메서드는 insert(index, value)처럼 지정한 index에 value값을 삽입합니다.

 

>>> list_var = [0, 1, 2, 3]
>>>
>>> list_var.insert(2, 555)
>>> list_var
[0, 1, 555, 2, 3]
>>>
>>> list_var.insert(0, "add first")
>>> list_var
['add first', 0, 1, 555, 2, 3]
>>>
>>> list_var.insert(len(list_var), "add last")
>>> list_var
['add first', 0, 1, 555, 2, 3, 'add last']

 

pop

pop 메서드는 pop([index])처럼 지정한 index의 요소를 추출합니다. 추출한 요소는 더 이상 리스트에 존재하지 않고 삭제됩니다. index를 지정하지 않으면 리스트의 마지막 항목을 추출합니다. 이러한 pop의 특성을 이용한다면 파이썬 리스트 구조를 스택 구조처럼 사용 가능합니다.

 

>>> list_var = list("CaptainBIN")
>>> list_var
['C', 'a', 'p', 't', 'a', 'i', 'n', 'B', 'I', 'N']
>>>
>>> list_var.pop(0)
'C'
>>>
>>> list_var
['a', 'p', 't', 'a', 'i', 'n', 'B', 'I', 'N']
>>> list_var.pop()
'N'
>>>
>>> list_var
['a', 'p', 't', 'a', 'i', 'n', 'B', 'I']

 

remove

remove메서드는 remove(value)와 같이 인자로 전달받은 value의 값에 해당하는 리스트 요소를 찾아 삭제합니다. 단, 동일한 값이 존재할 경우 인덱스가 작은 값만 삭제합니다. 만약 전달받은 value의 항목이 없다면 ValueError를 발생합니다.

 

>>> list_var = list("CaptainBIN")
>>> list_var
['C', 'a', 'p', 't', 'a', 'i', 'n', 'B', 'I', 'N']
>>> list_var.remove('a')
>>>
>>> list_var
['C', 'p', 't', 'a', 'i', 'n', 'B', 'I', 'N']
>>>
>>> list_var.remove('a')
>>> list_var
['C', 'p', 't', 'i', 'n', 'B', 'I', 'N']

 

reverse

리스트 객체의 요소들을 거꾸로 뒤집습니다.

 

>>> list_var = list("CaptainBIN")
>>> list_var
['C', 'a', 'p', 't', 'a', 'i', 'n', 'B', 'I', 'N']
>>>
>>> list_var.reverse()
>>>
>>> list_var
['N', 'I', 'B', 'n', 'i', 'a', 't', 'p', 'a', 'C']

 

sort

리스트의 항목들을 정렬합니다. 리스트 메서드의 파라미터는 sort(key=None, reverse=False)입니다. sort값은 문자 타입의 숫자는 숫자처럼 sort 되지 않음을 인지 해야 합니다.

 

# 숫자 타입 원소 sort
>>> list_var = [22, 9, 0, 120]
>>> list_var
[22, 9, 0, 120]
>>>
>>> list_var.sort()
>>> list_var
[0, 9, 22, 120]



# 문자열 타입 숫자 원소 sort
>>> list_var = ["22", "9", "0", "120"]
>>> list_var
['22', '9', '0', '120']
>>>
>>> list_var.sort()
>>> list_var
['0', '120', '22', '9']


# 문자열 길이를 key값으로 sort
>>> list_var.sort(key=len)
>>> list_var
['0', '9', '22', '120']


# reverse 옵션 활성화
>>> list_var.sort(key=len, reverse=True)
>>> list_var
['120', '22', '0', '9']

 

 

파이썬 리스트 컴프리헨션 (comprehension)

파이썬에서는 컴프리헨션이라는 조금 독특한 문법이 있습니다. 이는 요소를 생성하는 데 있어 간결하게 생성할 수 있도록 방법을 제공합니다. 간결한 문법요소 덕분에 한 줄에 표현할 수 있으며 한 줄 한 줄 읽는 파이썬 특성에 맞춰 컴프리헨션 실행 속도가 최적화되어 있습니다.

 

컴프리헨션은 사용하는 자료형에 따라 리스트 컴프리헨션(리스트컴프), 딕셔너리 컴프리헨션 (딕트컴프), 집합 컴프리헨션(세트 컴프)라고 불립니다.

 

튜플은 컴프리헨션이 없지만 만약 괄호로 둘러싸인 컴프리헨션이 있다면 그 코드는 생성기입니다.

 

다음은 리스트를 선언하고 1부터 10까지의 원소의 값을 두배 증가하는 코드입니다.

 

>>> list_var = []
>>> for i in range(1, 11):
...     list_var.append(i * 2)
...
>>> list_var
[2, 4, 6, 8, 10, 12, 14, 16, 18, 20]

 

만약 이 코드를 람다 함수를 사용하여 한 줄로 표현한다면 다음과 같이 코드를 작성할 수 있습니다.

 

>>> list_var = list(map(lambda v: v * 2, range(1,11)))
>>> list_var
[2, 4, 6, 8, 10, 12, 14, 16, 18, 20]

 

이 코드를 컴프리헨션으로 좀 더 간결히 표현한다면 다음과 같이 코드를 작성할 수 있습니다.

 

>>> list_var = [ i * 2 for i in range(1, 11)]
>>> list_var
[2, 4, 6, 8, 10, 12, 14, 16, 18, 20]

 

가독성을 놓고 보자면 람다나 컴프리헨션을 사용하지 않은 코드가 가독성이 훨씬 높아 보입니다. 하지만 3라인의 코드를 한 줄로 표현할 수 있는 코드를 무시할 수는 없을 것입니다. 또한 속도도 최적화되어 있다고 하니 필요할 때 적절히 사용하는 것도 좋을 것 같습니다. 

 

람다 표현 방식도 한 줄로 간결히 표현했지만 컴프리헨션 코드가 좀 더 간결해 보입니다.

 

이 컴프리헨션을 조금 응용하면 중첩으로도 사용 가능합니다.

 

>>> list_var = [
...     ['a', 'b', 'c', 'd', 'e'],
...     ['f', 'g', 'h', 'i', 'j'],
...     ['k', 'l', 'm', 'n', 'o'],
... ]
>>>
>>> list_var
[['a', 'b', 'c', 'd', 'e'], ['f', 'g', 'h', 'i', 'j'], ['k', 'l', 'm', 'n', 'o']]
>>>
>>> [[i[j] for i in list_var] for j in range(5)]
[['a', 'f', 'k'], ['b', 'g', 'l'], ['c', 'h', 'm'], ['d', 'i', 'n'], ['e', 'j', 'o']]

 

파이썬 컴프리헨션 성능 체크

from timeit import timeit as tt

# 기본 코드
>>> org_code="""
... list_var = []
... for i in range(1, 11):
...     list_var.append(i * 2)
... """


# 람다 사용 코드
>>> lambda_code="""
... list_var = list(map(lambda v:v * 2, range(1, 11)))
... """


# 컴프리헨션 코드
>>> compre_code="""
... list_var = [ i * 2 for i in range(1, 11)]
... """


########################
# 코드 실행시간 체크
########################
# 기본코드 수행 시간
>>> tt(org_code)
1.344222800000125
>>> tt(org_code)
1.3156508999998096
>>> tt(org_code)
1.3431496000000607

# 람다 코드 수행 시간
>>> tt(lambda_code)
1.7593600000000151
>>> tt(lambda_code)
1.7624657999999727
>>> tt(lambda_code)
1.7633382999999867

# 컴프리헨션 코드 수행 시간
>>> tt(compre_code)
1.0033501999998862
>>> tt(compre_code)
1.0277619999999388
>>> tt(compre_code)
1.0009276999999202

 

성능 체크로 각 3가지의 코드를 각각 3번씩 수행하였습니다. 성능 체크 결과 컴프리헨션 문법은 파이썬에서 속도 최적화되었다는 말이 사실이라는 것이 입증되었습니다. 다소 문법이 생소하여 가독성이 조금 떨어지는 경향이 있지만 자주 사용하다 보면 눈에 익을 것이므로 간결성과 속도 두 마리 토끼를 동시에 잡는 문법이 바로 이 컴프리헨션이 아닐까? 하는 생각이 듭니다.

MORE