Post

(python) List, Tuple, Dictionary, Set, Enumerate, sort 정렬

list()함수를 이용해 다른 데이터 타입을 리스트로 변환할 수 있다. tuple()함수를 이용해 다른 데이터 타입을 투플로 변환할 수 있다. dict()함수를 이용해 두 값으로 이루어진 시퀀스를 딕셔너리로 변환할 수 있다.

항목 삭제
1
2
3
4
del arr[offset]
arr.pop(offset)
arr.remove(value)    # 값으로 삭제

값을 이용해 인덱스 알아내기
1
2
arr.index(value)

Array

파이썬 기본 리스트 []는 array 보다는 linked list에 가깝다. array를 사용하기 위해서는arraynumpy 를 사용해야 한다. numpy는 좋은 라이브러리이지만, 서드파티 라이브러리를 쓰기 애매한 경우 array도 효율적이다.

List

정적 언어의 리스트와 달리아무 타입이나 리스트에 담을 수 있다 .

1
2
3
4
5
a[0] = 1
a[1] = "str"
a[2] = [2, 3.3]
a[3] = ("a", 0)

리스트 생성

1
2
li = [1] \* len(5)

리스트에 항목 추가 : append() ( push()가 아니다 )

1
2
3
4
5
li = [[1, 2, 3],
[4, 5, 6]]
li[0].append([7, 8])
[[1, 2, 3, [7, 8]], [4, 5, 6]

이는 a[len(a):] = [x]와 같다.

리스트 간 병합 : += 또는 extend()

1
2
3
4
5
li = [[1, 2, 3],
[4, 5, 6]]
li[0] += [7, 8]
[[1, 2, 3, 7, 8], [4, 5, 6]

문자열, 배열 reverse

세가지 방법이 있다.

1
2
3
step[::-1]        # 제일 빠름
list.reverse()    # 리스트 형식이 아닌 모든 iterator( e.g. OrderDict() )에 사용 가능

1
2
3
4
5
reversed(sequence) class # 반대로 정렬한 key로만 이루어진 iterator를 반환하기 때문에, 이를 원래 dict의 index로 사용한다.
rev\_key = reversed(dic)
for i in rev\_key:
print(dic[i])

range downto
1
2
3
>>> range(0, -10, -1)
[0, -1, -2, -3, -4, -5, -6, -7, -8, -9]

리스트 복사

C에서 a, b가 배열일 때 b = a와 같이 쓰면 같은 객체를 가리키게 되는 것 처럼 파이썬도 그렇다. 따라서 같은 내용을 가진 다른 리스트를 얻고 싶다면 C에서 memcpy를 사용해야 하는 것처럼, 파이썬에서는 b=a.copy(), b=list(a), b=[0:]를 사용할 수 있다.

index()

리스트에는 find()가 없다.

1
2
3
4
5
try:
l.index(8)
except ValueError:
print('error')

언패킹, 구조 분해 선언(destructuring declaration)

리스트나 투플은 한꺼번에 변수에 할당할 수 있는데, 이를 언패킹 또는 구조 분해 선언이라고 한다.

1
2
a, b, c = arr

근데, 딱 리스트나 투플의 요소 개수만큼 변수가 있어야한다. 적어서는 안된다. 이를 이용해 투플을 정의함과 동시에 값을 할당해서 두 변수의 값을 교환할 수 있다. a, b = b, a

tuple

  • 투플은 주로 딕셔너리 키로 사용할 수 있다.
  • 함수의 인자들은 투플로 감싸져 전달된다.

원래 투플은 불변인데… 다음과 같은 거지같은 방법을 사용하면 투플에 새로운 원소를 추가할 수 있다. ….는 것 처럼 보이지만 사실 보면 그냥 새로운 객체가 할당되는거다. 아주 좋지 않은 방법인 것 같은데 이런 식으로 쓰도록 유도하는 라이브러리가 있다. 바로 plotly다.

1
2
3
4
5
6
7
8
9
>>> a = ()
>>> id(a)
2046389583944
>>> a += tuple([1])
>>> a
(1,)
>>> id(a)
2044641417424

dictionary

주의해야 할 점. dict는 key가 동적으로 결정되고 이 key를 이용해 컨테이너의 원소에 접근해야 하는 경우에 유용하다. 단순히 내부에 데이터가 있는지를 체크하는건 리스트도 in으로 검사 가능함.

딕셔너리 == 맵 (map) == 연관 배열 == 연상 배열 모두 같은 말이다. { key:value } 로 정의한다.

자주 쓰게 되는 메서드
1
2
3
4
dict.keys()
dict.values()    ==> list(dict.values())
dict.items()     ==> for key, value in dict.items():

1. 딕셔너리의 키는 반드시 유일해야 한다.

같은 키가 두개 있다면 이후에 정의된 키에 연결된 값이 출력된다.

2. 항목들의 순서를 따지지 않는다.

순서가 있는 dict가 필요하다면 collections.OrderedDict()를 사용한다. 또는 list(dic.values())로 값만 리스트로 반환받는 방법도 있다.

key 지정 패턴

key는 문자열로 지정하는데, 이런식으로도 사용 가능하다

1
2
self.layers['Affine' + str(idx)]

dic[key] dic.get(key)

dic[key]key가 없을 경우 오류 발생 dic.get(key)None또는 지정한 default 값을 반환

이를 이용해 딕셔너리에 키가 존재하는지 dic.get()을 사용해 확인할 수 있다. 그러나 다음 처럼 하는게 더 나은게, 불필요한 반환이 발생하지 않으니까.

1
2
if 'key' in dic:

set

유일한 값을 가진 리스트를 만들고 싶다면 집합(set, 셋)을 사용한다. 교집합, 합집합, 차집합, 대칭 차집합 등을 지원한다.

열거형

1
2
3
enumerate(iterable[, start]) -> iterator for index, value of iterable
Return an enumerate object.

enumarate object를 반환하는 함수 형태로 제공된다.index와 value를 한꺼번에 반환 한다는 점이 특징.

다음 처럼 주로 for문과 같이 사용한다.

1
2
3
4
5
6
7
>>> for i, name in enumerate(['body', 'foo', 'bar']):
...     print(i, name)
...
0 body
1 foo
2 bar

주의할 점은 enumarate는 한번 사용하면 소비되어 없어져 버린다는 것이다.

그래서 for문에서만 사용할 목적이면 저런 식으로 변수에 할당 안하고 바로 사용하고, 계속 사용해야 한다면 다음과 같이 list나 tuple 등에 넣어서 사용한다.

1
2
3
4
enum = tuple(enumerate(['body', 'foo', 'bar']):)
print(enum)
((0, 'name'), (1, 'cha'), (2, 'che'))

정렬 sort, sorted

1
2
3
sort()     # 리스트 자체를 정렬
sorted()   # 정렬된 복사본을 반환

1
2
3
4
>>> t = [('f0', 0), ('f2', 2), ('f1', 1)]
>>> sorted(t, key=lambda x : x[0])
[('f0', 0), ('f1', 1), ('f2', 2)]

key에는 함수가 들어가야 하며, t의 인자가 하나 씩 전달된다. 정렬 기준이 두 개 이상 등 복잡한 경우 아래 operator를 사용한다.

1
2
3
4
from operator import itemgetter, attrgetter, methodcaller
sorted(li, key=itemgetter(0, 1), reverse=True)
li.sort(key=itemgetter(0, 1), reverse=True)

zip

1
2
3
4
5
6
>>> li = [['a', 'b', 'c'], [1, 2, 3]]
>>> list(zip(li[0], li[1]))
[('a', 1), ('b', 2), ('c', 3)]
>>> list(zip(\*li))
[('a', 1), ('b', 2), ('c', 3)]

이를 이용해 transpose할 수 있다. 아웃풋이 tuple이므로, transposed가 수정 가능해야 한다면

1
2
transpose = lambda data: [[row[i] for row in data] for i in range(len(data[0]))]

\*는 임의의 인자를 unpacking하는 연산자다. 인자로 넘길 때, 파라미터로 받을 때 모두 사용할 수 있다. (\*arg) 다음과 같은 상황 등 여러모로 유용하게 사용할 수 있다.

1
2
tbl\_t.insert(0, ["Node", \*[col for col in self.traces.keys()]])

\*\*도 마찬가지이며, 딕셔너리를 unpacking한다. (\*\*kwarg)

namedtuple

from collections import namedtuple은 객체 대신 간단한 용도로 쓸 수 있다. 클래스를 만들기에는 너무 간단한 필드만 있어 뭔가 맘에 안들고, 그렇다고 딕셔너리를 쓰자니 [문자열]을 써주는 데서 필드를 강제할 수 없다는 점이 마음에 안들고 하는 경우, namedtuple을 사용해 해결하면 된다! 예를 들면 다음과 같은 케이스. 이런 경우 namedtuple을 쓰자.

1
2
3
4
self.session[session\_name] = {}
self.session[session\_name]["sock"] = sock
self.session[session\_name]["qwer"] = asdf

근데 namedtuple은 \_\_slots\_\_를 정의해버리기 때문에 attribute 추가 안되고, 초기화 로직을 따로 써줘야 한다는 명백한 차이가 있으므로 클래스와 잘 구분해서 써야 함.

This post is licensed under CC BY 4.0 by the author.