`` list()``함수를 이용해 다른 데이터 타입을 리스트로 변환할 수 있다.

`` tuple()``함수를 이용해 다른 데이터 타입을 투플로 변환할 수 있다.

`` dict()``함수를 이용해 두 값으로 이루어진 시퀀스를 딕셔너리로 변환할 수 있다.


항목 삭제

```python
del arr[offset]
arr.pop(offset)
arr.remove(value)    # 값으로 삭제
```

값을 이용해 인덱스 알아내기

```python
arr.index(value)
```

Array

파이썬 기본 리스트 `` []``는 array 보다는 linked list에 가깝다.

array를 사용하기 위해서는 array나 numpy를 사용해야 한다. 

numpy는 좋은 라이브러리이지만, 서드파티 라이브러리를 쓰기 애매한 경우 array도 효율적이다.


List

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

```python

a[0] = 1

a[1] = "str"

a[2] = [2, 3.3]

a[3] = ("a", 0)

```


리스트 생성
```python
li = [1] * len(5)
```

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

```python

li = [[1, 2, 3],

      [4, 5, 6]]

li[0].append([7, 8])

[[1, 2, 3, [7, 8]], [4, 5, 6]

```

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


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

```python

li = [[1, 2, 3],

      [4, 5, 6]]

li[0] += [7, 8]

[[1, 2, 3, 7, 8], [4, 5, 6]

```


문자열, 배열 reverse

세가지 방법이 있다.

```python

step[::-1]        # 제일 빠름

list.reverse()    # 리스트 형식이 아닌 모든 iterator( e.g. OrderDict() )에 사용 가능

```

```python

reversed(sequence) class # 반대로 정렬한 key로만 이루어진 iterator를 반환하기 때문에, 이를 원래 dict의 index로 사용한다.

rev_key = reversed(dic)

for i in rev_key:

    print(dic[i])

```


range downto

```python

>>> 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()

리스트에는 ``python find()``가 없다.
```python
try:
    l.index(8)
except ValueError:
    print('error')
```


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

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

```python

a, b, c = arr

```

근데, 딱 리스트나 투플의 요소 개수만큼 변수가 있어야한다. 적어서는 안된다.

이를 이용해 투플을 정의함과 동시에 값을 할당해서 두 변수의 값을 교환할 수 있다.

``python a, b = b, a``


tuple

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


원래 투플은 불변인데... 다음과 같은 거지같은 방법을 사용하면 투플에 새로운 원소를 추가할 수 있다.

....는 것 처럼 보이지만 사실 보면 그냥 새로운 객체가 할당되는거다.

아주 좋지 않은 방법인 것 같은데 이런 식으로 쓰도록 유도하는 라이브러리가 있다. 바로 plotly다.

```python

>>> a = ()

>>> id(a)

2046389583944

>>> a += tuple([1])

>>> a

(1,)

>>> id(a)

2044641417424

```


dictionary

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

딕셔너리 == 맵 (map) == 연관 배열 == 연상 배열 모두 같은 말이다.

`` { key:value }`` 로 정의한다.


자주 쓰게 되는 메서드

```py

dict.keys()

dict.values()    ==> list(dict.values())

dict.items()     ==> for key, value in dict.items():

```


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

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


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

순서가 있는 dict가 필요하다면 ``python collections.OrderedDict()``를 사용한다.

또는 ``python list(dic.values())``로 값만 리스트로 반환받는 방법도 있다.


key 지정 패턴

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

```python

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

```


dic[key] dic.get(key)

``python dic[key]``는 ``key``가 없을 경우 오류 발생

``python dic.get(key)``는 ``python None`` 또는 지정한 ``default`` 값을 반환


이를 이용해 딕셔너리에 키가 존재하는지 ``python dic.get()``을 사용해 확인할 수 있다.

그러나 다음 처럼 하는게 더 나은게, 불필요한 반환이 발생하지 않으니까.

```python

if 'key' in dic:

```


set

유일한 값을 가진 리스트를 만들고 싶다면 집합(set, 셋)을 사용한다.

교집합, 합집합, 차집합, 대칭 차집합 등을 지원한다.


열거형

```python

enumerate(iterable[, start]) -> iterator for index, value of iterable

Return an enumerate object.

```

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


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

```python

>>> for i, name in enumerate(['body', 'foo', 'bar']):

...     print(i, name)

...

0 body

1 foo

2 bar

```


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

그래서 for문에서만 사용할 목적이면 저런 식으로 변수에 할당 안하고 바로 사용하고, 

계속 사용해야 한다면 다음과 같이 list나 tuple 등에 넣어서 사용한다.

```python

enum = tuple(enumerate(['body', 'foo', 'bar']):)

print(enum)

((0, 'name'), (1, 'cha'), (2, 'che'))

```


정렬 sort, sorted

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

```python
>>> t = [('f0', 0), ('f2', 2), ('f1', 1)]
>>> sorted(t, key=lambda x : x[0])
[('f0', 0), ('f1', 1), ('f2', 2)]
```
`` key``에는 함수가 들어가야 하며, `` t``의 인자가 하나 씩 전달된다.

정렬 기준이 두 개 이상 등 복잡한 경우 아래 operator를 사용한다.
```python
from operator import itemgetter, attrgetter, methodcaller

sorted(li, key=itemgetter(0, 1), reverse=True)
li.sort(key=itemgetter(0, 1), reverse=True)
```


zip

```python
>>> 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가 수정 가능해야 한다면

```python

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

```


``c *``는 임의의 인자를 unpacking하는 연산자다. 인자로 넘길 때, 파라미터로 받을 때 모두 사용할 수 있다. (``c *arg``)

다음과 같은 상황 등 여러모로 유용하게 사용할 수 있다.

```python

tbl_t.insert(0, ["Node", *[col for col in self.traces.keys()]])

```


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


namedtuple

``python from collections import namedtuple``은 객체 대신 간단한 용도로 쓸 수 있다.

클래스를 만들기에는 너무 간단한 필드만 있어 뭔가 맘에 안들고, 그렇다고 딕셔너리를 쓰자니 [문자열]을 써주는 데서 필드를 강제할 수 없다는 점이 마음에 안들고 하는 경우, namedtuple을 사용해 해결하면 된다!
예를 들면 다음과 같은 케이스. 이런 경우 namedtuple을 쓰자.
```python
self.session[session_name] = {}
self.session[session_name]["sock"] = sock
self.session[session_name]["qwer"] = asdf
```

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