목차
Python Data Structure
Stack
- 나중에 넣은 데이터를 먼저 반환하도록 설계된 메모리 구조 (LIFO, Last In First Out)
- 데이터 입력을 push, 출력을 pop 이라 함
- list 로 스택 가능
- list.append()
- list.pop() : 특이한게 리턴 (나오는 값) 이 있으면서도 리스트가 변함
Queue
- 먼저 넣은 데이터를 먼저 반환하도록 설계된 메모리 구조 (FIFO, First In First Out)
- 스택과 반대되는 개념
- 리스트를 사용하여 큐 구조 가능
- list.append()
- list.pop(0) : 처음 원소 빠짐, O(N) 으로 비효율적
- collections.deque 로 queue 사용하도록 하자
- deque.append()
- deque.popleft()
Tuple
- 값의 변경이 불가능한 리스트
- 선언시 [] 가 아닌 () 를 사용
- 리스트의 연산, 인덱싱, 슬라이싱 등을 동일하게 사용
- 왜 쓸까?
- 프로그램을 작동하는 동안 변경되지 않는 데이터 저장
- 함수의 리턴값 등 사용자의 실수에 의한 에러를 사전에 방지
Set
- 값을 순서없이 저장, 중복 허용하지 않는 자료형
- set([1, 2]) 로 선언
- 내장 함수
- add : 한 원소 추가
- remove : 한 원소 삭제
- update : 한 번에 원소들 추가
- s1.union(s2) or s1 (shift) s2 : 합집합
- s1.intersection(s2) or s1 & s2 : 교집합
- s1.difference(s2) or s1 - s2 : 차집합
Dict
- 데이터를 키와 밸류로 함께 저장
- 키는 데이터 고유 값, Identifier !
- dict() or {} 로 선언
- {key1 : value1, key2 : [value2, value3]}
- 내장 함수
- items : tuple 형태로 키 밸류가 나옴, 반복문에서 언패킹 k, v 해서 많이 사용
- keys : key 값들만 묶여서 나옴
- values : values 값들만 묶여서 나옴
실습 : Command Analyzer
- 커맨드 명령어 분석
Collections
- List, Tuple, Dict 에 대한 파이썬 빌트인 확장 자료 구조 (모듈)
- 편의성, 실행 효율 제공
- 목록
- deque
- Counter
- OrderedDict
- defaultdict
- namedtuple
deque
- 스택과 큐를 동시에 지원하는 모듈
- 리스트에 비해 효율적인 자료 저장 방식 적용
- 링크드 리스트 특성 지원
- 기존 리스트 함수 모두 지원
defaultdict
-
일반 딕트는 키값이 생성되지 않으면 에러가 나는데, 디폴트 딕트는 키값 없으면 디폴트 값을 넣어줌
from collections import defaultdict d = defaultdict(lambda : 0) d["aa"] # 0
-
텍스트에서 데이터 마이닝할 때 딕트나 디폴트 딕트 이용하면 편리함
Counter
- sequence type 의 데이터 엘리멘트 개수를 세주는 모듈
- set 의 연산 지원 (합, 교, 차집합)
namedtuple
- tuple 형태로 데이터 구조체를 저장하는 방법
-
저장되는 데이터의 variable 을 사전에 지정해서 저장
Point = namedtuple('Point', ['x', 'y']) p = Point(x=11, y=22) p[0], [1] # (11, 22) p # (Point(x=11, y=22) p.x + p.y # 33
Pythonic Code
- 파이썬 스타일의 코딩법
- 파이썬 특유의 문법을 활용하여 효율적으로 코드를 표현함
- 이제는 많은 언어들이 서로의 장점을 채용, 고급 코드 작성할 때 더 많이 필요해짐
- 컴퓨터에게 시간이 더 들어도 사람의 시간은 덜 들어서 좋음
- 왜 쓰는가?
- 다른 사람 코드에 대한 이해도 (많은 개발자들이 파이썬 스타일로 코딩함)
- 효율성 (속도도 빠르고 익숙해지면 코드도 짧아짐)
- 간지 (잘 짜는 거처럼 보임)
split & join
- split
- string type 의 값을 기준값으로 나눠서 list 형태로 변환
- join
- 스트링 리스트를 기준값으로 붙여서 스트링으로 변환
list comprehension
- 기존 리스트를 사용하여 간단히 다른 리스트를 만드는 기법 (포괄적인 리스트, 포함되는 리스트라는 의미)
- 파이썬에서 가장 많이 사용되는 기법 중 하나
- 일반적으로 for + append 보다 속도가 빠름
- Nested For loop
- a = [i*j for i in range(1, 3) for j in range(10, 30, 10)] # [10, 20, 20, 40]
- Filter (조건)
- a = [i for i in range(10) if i % 2 == 0] # 0~9 중 짝수만 a 에 넣기
- 2차원 for loop
- a = [[i+j for i in range(5) if i % 2 == 0] for j in range(5) if i % 2 == 1]
pprint
- 이쁘게 출력
import pprint
pprint.pprint(a)
enumerate & zip
-
enumerate : 리스트의 엘리먼트를 추출할 때 번호를 붙여서 추출
for i, v in enumerate("ABC") print(f"{v} : {i}") # A : 0 # B : 1 # C : 1
-
zip : 두 개의 리스트 값을 병렬적으로 추출 (집은 제너레이터라 리스트로 감싸줘야함)
a = ["a", "b", "c"] b = ["A", "B", "C"] [c for c in zip(a, b)] # [("a", "A"), ("b", "B"), ("c", "C")]
lambda & map & reduce
- lambda : 함수 이름 없이, 함수처럼 쓸 수 있는 익명함수 (사실 파이썬3 부터 권장안함, 하지만 많이쓰임)
- f = lambda x, y: x + y
- 어려운 문법, 테스트도 어려움, 문서화 docstring 지원 미비 등 문제가 있다.
- map : 두 개 이상의 리스트에도 적용 가능, if filter 도 사용가능 (최근에는 리스트 컴프리헨션으로 쓰는게 낫다 말하지만 많이 씀)
- list(map(함수, 리스트1, 리스트2..) : 원소들에 대해 함수 적용
-
reduce : 맵과 달리 리스트에 똑같은 함수를 적용해서 통합 (직관성이 떨어져서 평소엔 많이 안쓰임, 대용량 데이터 다룰 때 씀)
from functools import reduce print(reduce(lambda x, y: x+ y, [1, 2, 3, 4, 5])) # 15
Iterable Object
- Sequence형 자료형에서 데이터를 순서대로 추출하는 object
- 내부적으로 iter 와 next 함수로 구현됨
- iter 는 메모리 구조를 가지고 옴
- next는 메모리를 참고해서 값을 가져옴, 그리고 메모리 다음으로 옮김
- 리스트 객체는 한 뭉치의 메모리가 있고 각각 주소에서 자기 값에 해당하는 주소를 바라보는 형태
Generator
- 효율적인 메모리 사용, 일반적으로 제너레이터 권장
import sys
def general_list(v):
result = []
for i in range(v):
result.append(i)
return result
a = general_list(50)
sys.getsizeof(a) # 520 (Bytes)
def generator_list(v):
result = []
for i in range(value):
yield i # 호출할 때 데이터를 출력해줌
b = generator_list(50) # 평소엔 메모리 주소값만 가지고 있다가 호출될 때마다 던져줌, 효율적
sys.getsizeof(b) # 112 (Bytes)
- generator comprehension (= generator expression)
- 리스트 컴프리헨션과 유사한 형태로 제너레이터 형태의 리스트 생성
- 대신 ( ) 사용
gen_ex = (n*n for n in range(500)) type(gen_ex) # generator, 주소만 있고 메모리 할당은 안함 list(gen_ex) # 메모리 생성
- 왜 쓸까? 일반적인 iterator 보다 훨씬 적은 메모리 사용
- 언제 쓸까?
- 리스트 타입의 데이터를 반환해주는 함수는 generator로 만들어라 (yield)
- 읽기 쉬운 장점, 중간 과정에서 loop 이 중단될 수 있을 때
- 큰 데이터 처리할때 generator expression 고려할 것
- 파일 데이터 처리할 때도 generator 쓰자
- 리스트 타입의 데이터를 반환해주는 함수는 generator로 만들어라 (yield)
Function passing arguments
- Keyword arguments
- 함수에 입력되는 파라미터의 변수명을 사용, 아규먼트를 넘김
- func(x = 10)
- Default arguments
- 파라미터의 기본 값 사용, 넣어주면 넣은 값 사용
- def func(x = 1):
- Variable-length asterisk (가변길이 에스터리스크*)
-
함수의 파라미터가 정해지지 않음 (다항 방정식 등)
→ Asterisk(*) 를 사용하여 개수가 정해지지 않은 변수를 함수의 파라미터로 사용
-
입력된 값은 tuple type 으로 사용 가능
def asterist_test(a, b, *args): return a+b+sum(args) print(asterisk_test(1, 2, 3, 4, 5) # 15K
-
- Keyword variable-length (키워드 가변인자)
- 파라미터 이름을 따로 지정하지 않고 입력
- Astserisk 2개 사용
- 입력된 값은 dict_type으로 사용
- 가변인자는 오직 한 개만 기존 가변인자 다음에 사용
def kwargs_test(**kwargs): print(kwargs) print(type(kwargs)) kwargs_test(first=3, second=4, third=5) # {'first' : 3, 'second' : 4, 'third' : 5} # <class 'dict'> def kwargs_test_2(one, two, *args, **kwargs): print(one + two + sum(args)) kwargs_test_2(10, 30, 3, 5, 6, 7, first = 3, second = 4, third = 5) # one = 10, two = 30, args = (3, 5, 6, 7), kwargs = {'first' : 3, 'second' : 4, 'third' : 5} # 가변인자 순서 지켜줘야 함
asterisk 의 또다른 기능 - unpacking a container
- tuple, dict 등 자료형에 들어가 있는 값을 언패킹
-
함수의 입력값, zip 등에 유용하게 사용가능
def ast1(a, *args): print(a, args) print(type(args)) test = (2, 3, 4, 5) ast1(1, *test) # 입력할 때 별표치면 풀려서(언패킹) 들어감 # 1 (2, 3, 4, 5) <class 'tuple'> def ast2(a, args):
- 함수 입력할 때 변수에 * 를 붙이면 풀려서 들어간다.
-
- 두 개 쓰면 dict key = value 됨
피어 세션
-
- Generator 의 yield 는 어떻게 메모리를 할당하고 어떤 방식으로 동작하는가?
- 아직 답을 못찾아서 따로 블로깅 예정!
-
- 이론에서는 메모리 공간에 관해 배우는데 일상적으로 메모리 (공간) 를 고려하는 일이 많지 않아보이는데 어떤 상황에서 고려해야할까
- IoT 나 임베디드 컴퓨팅 같이 하드웨어가 작을 때!
느낀점
파이써닉한 코딩
리스트 컴프리헨션부터 애스터리스크 인자까지 다양한 파이썬만의 코딩 스타일을 배울 수 있었다. 기존에 딥러닝 모델 적용과 코딩테스트를 하면서 리스트 컴프리헨션 정도는 눈치껏 배웠었다. 하지만 zip 이나 map 이 파이써닉 한 것인지 몰랐고, 애스터리스크 문법은 처음 배우는 것이라 유익했다.
스타일 변화
기존에 하던 습관을 바꾸기란 참 쉽지 않다. 조원들을 보면서 마크다운을 더 잘 써가며 블로깅 해야할 필요성과 모르는 부분에 있어서 대충 알지 않고 끝까지 파고들어 알아내는 습관을 기르고 싶다는 생각이 들었다. 또 파이써닉 코딩 스타일을 보면서 더 멋지게 코딩해야함을 배웠다. 사실 기존 습관이 익숙하다는 것은 귀찮음에 기반한 핑계임을 안다. 습관 바꾸기 쉽지 않겠지만 더 발전하기 위해 변화를 주리라.