Python Intermediate Programming
3.0. Sequence type
컨테이너 vs 플랫
Container: 서로다른 자료형: list, tuple, collections.deque
Flat: 한 개의 자료형 str, bytes, bytearray, array.array, memoryview
가변 vs 불변
Mutable: list, bytearray, array.array, memoryview, deque
Immutable: tuple, str, bytes
얕은 복사 vs 깊은 복사
리스트 생성 시 for문으로 재귀적으로 생성과 * 연산으로 생성 차이
marks1 = [['A'] * 5 for n in range(5)]
marks2 = [['A'] * 5] * 5
print(marks1)
> [['A', 'A', 'A', 'A', 'A'], ['A', 'A', 'A', 'A', 'A'], ['A', 'A', 'A', 'A', 'A'], ['A', 'A', 'A', 'A', 'A'], ['A',
'A', 'A', 'A', 'A']]
print(marks2)
> [['A', 'A', 'A', 'A', 'A'], ['A', 'A', 'A', 'A', 'A'], ['A', 'A', 'A', 'A', 'A'], ['A', 'A', 'A', 'A', 'A'], ['A',
'A', 'A', 'A', 'A']]
# 값 변경
marks1[0][1] = 'X'
marks2[0][1] = 'X'
print(marks1)
> [['A', 'X', 'A', 'A', 'A'], ['A', 'A', 'A', 'A', 'A'], ['A', 'A', 'A', 'A', 'A'], ['A', 'A', 'A', 'A', 'A'], ['A',
'A', 'A', 'A', 'A']]
print(marks2)
> [['A', 'X', 'A', 'A', 'A'], ['A', 'X', 'A', 'A', 'A'], ['A', 'X', 'A', 'A', 'A'], ['A', 'X', 'A', 'A', 'A'], ['A',
'X', 'A', 'A', 'A']]
# id값 차이 확인
print([id(i) for i in marks1])
> [1817473083648, 1817473082944, 1817473083136, 1817473083584, 1817473083712]
print([id(i) for i in marks2])
> [1817473087040, 1817473087040, 1817473087040, 1817473087040, 1817473087040]
shallow copy: 객체 껍데기만 복사하고 내용은 동일한 객체 참조
mutable한 list의 경우 수정되고, immutable한 tuple의 경우 별도의 객체에 저장됨
import copy
a = [1, [1, 2, 3]]
b = copy.copy(a) # shallow copy
print(b)
> [1, [1, 2, 3]]
b[0] = 100 # immutable tuple 수정
print(b)
> [100, [1, 2, 3]]
print(a) # immutable tuple의 경우 복사본만 수정
> [1, [1, 2, 3]]
c = copy.copy(a) # shallow copy
c[1].append(4) # mutable list 수정
print(c)
> [1, [1, 2, 3, 4]]
print(a) # mutable list의 경우 둘 다 값이 변경됨
> [1, [1, 2, 3, 4]]
deep copy: 객체 복사 후 내용도 재귀적으로 복사
mutable, immutable 상관없이 별도의 객체에 저장됨
a = [1, [1, 2, 3]]
b = copy.deepcopy(a) # deep copy
print(b)
> [1, [1, 2, 3]]
b[0] = 100
b[1].append(4)
print(b)
> [100, [1, 2, 3, 4]]
print(a)
> [1, [1, 2, 3]]
3.1. Generator
한 번에 한 개의 항목을 생성(메모리 유지X)
Generator 생성
chars = 'abc'
tuple_g = (ord(s) for s in chars)
print(tuple_g)
> <generator object <genexpr> at 0x000001A729CF75F0>
type(tuple_g)
> <class 'generator'>
print(next(tuple_g))
> 97
print(next(tuple_g))
> 98
print(next(tuple_g))
> 99
print(next(tuple_g))
> StopIteration Error
3.2. Tuple Advanced
unpacking
x, y, *rest = range(10)
print(x, y, rest)
> 0 1 [2, 3, 4, 5, 6, 7, 8, 9]
3.3. HashTable
적은 리소스로 많은 데이터를 효율적으로 관리 중복 허용 안되는 데이터 타입들 (Dict, Set)
Set vs List
t1 = (10, 20, (30, 40, 50))
t2 = (10, 20, [30, 40, 50])
print( hash(t1))
> 465510690262297113
print( hash(t2)) # hash error남
setdefault 미사용 (dict)
source = (('k1', 'val1'),
('k1', 'val2'),
('k2', 'val3'),
('k2', 'val4'),
('k2', 'val5'))
new_dict1 = {}
for k, v in source:
if k in new_dict1:
new_dict1[k].append(v)
else:
new_dict1[k] = [v]
print(new_dict1)
> {'k1': ['val1', 'val2'], 'k2': ['val3', 'val4', 'val5']}
setdefault 사용
new_dict2 = {}
for k, v in source:
new_dict2.setdefault(k, []).append(v)
print(new_dict2)
> {'k1': ['val1', 'val2'], 'k2': ['val3', 'val4', 'val5']}
3.4. Dict & Set Advanced
# immutable Dict
from types import MappingProxyType
d = {'key1': 'value1'}
# Read Only
d_frozen = MappingProxyType(d)
print(d, id(d))
> {'key1': 'value1'} 1817473569408
print(d_frozen, id(d_frozen))
> {'key1': 'value1'} 1817472793280
print(d is d_frozen, d == d_frozen)
> False True
# 수정 불가
d_frozen['key1'] = 'value2' # mappingproxy 객체는 assign지원하지 않는다는 error
d['key2'] = 'value2'
print(d)
> {'key1': 'value1', 'key2': 'value2'}
s1 = {'Apple', 'Orange', 'Apple', 'Orange', 'Kiwi'}
s2 = set(['Apple', 'Orange', 'Apple', 'Orange', 'Kiwi'])
s3 = {3}
s4 = set() # Not {}
s5 = frozenset({'Apple', 'Orange', 'Apple', 'Orange', 'Kiwi'})
# 추가
s1.add('Melon')
# 추가 불가
s5.add('Melon') # frozenset은 add 속성 존재하지 않는다는 error
print(s1, type(s1))
> {'Orange', 'Apple', 'Kiwi', 'Melon'} <class 'set'>
print(s2, type(s2))
> {'Orange', 'Apple', 'Kiwi'} <class 'set'>
print(s3, type(s3))
> {3} <class 'set'>
print(s4, type(s4))
> set() <class 'set'>
print(s5, type(s5))
> frozenset({'Orange', 'Apple', 'Kiwi'}) <class 'frozenset'>