ai tech 3일차
강의
# 스택
나중에 넣은 데이터를 먼저 반환하도록 설계된 메모리 구조
데이터의 입력을 push, 출력을 pop이라고 함
파이썬에서는 리스트를 사용하여 스택구조 구현
a = [1, 2, 3, 4, 5]
a.append(10) # a == [1, 2, 3, 4, 5, 10]
b = a.pop() # b==10, a == [1, 2, 3, 4, 5]
# 큐
먼저 넣은 데이터를 먼저 반환하도록 설계된 메모리 구조
파이썬에서는 리스트를 사용하여 큐 구조 구현
a.append(10)
a.pop(0)
# 튜플
값의 변경이 불가능한 리스트
리스트의 연산, 인덱싱, 슬라이싱은 모두 사용 가능하다.
# 집합
값을 순서없이 저장, 원소의 중복은 제거된다.
a.add(b) # b를 원소로 추가한다.
a.remove(b) # b를 원소에서 삭제한다. b가 원소로 없을때에는 에러가 발생한다.
a.discard(b) # b가 원소로 있으면 없어지고 없더라도 에러가 발생하지 않는다.
a.update([1,2,3,4,5]) # 새로운 원소 뭉탱이를 추가한다.
s1.union(s2) # 합집합
s1 | s2 # 합집합
s1.intersection(s2) # 교집합
s1 & s2 # 합집합
s1.difference(s2) # 차집합
s1 - s2 # 차집합
# 사전
key값과 value값을 동시에 저장
다른 언어에서는 해시테이블이라는 용어를 사용
a.items()
a.keys()
a.items()
a.values()
# collection 모듈
from collections import deque
from collections import Counter
from collections import OrderedDict
from collections import defaultdict
from collection import namedtuple
# deque
from collections import deque
a = deque()
a.appendleft(b)
a.popleft(b)
a.rotate(1)
a.extend([1,2,3])
a.extendleft([1,2,3])
# OrderedDict
사전에 입력되는 순서를 보장하지만, 현재는 기본 dict도 지원된다.
# defaultdict
사전의 초기값을 넣어주며, 없는 키를 요청할때 기본값으로 value를 만들어준다.
초기값은 lambda: 0 과 같이 defaultdict를 만들때 람다로 적어준다.
# Counter
시퀀스 데이터 타입에서 element의 갯수를 세준다.
거꾸로 Counter에서 선언하고 시퀀스 데이터로 뺄 수도 있다.
c = Counter(cats=1, dogs=1)
print(list(c.elements()))
['cats', 'dogs', 'dogs']
set에서 사용하는 연산들이 그대로 사용 가능하다.
a.subtract(b)
# namedtuple
튜플 형태로 데이터를 구조체를 저장하는 방법
칼럼정보를 넣어서 보여줄수 있다는 장점이 있다.
Point = namedtuple('Point', ['x', 'y'])
p = Point(11, y=22)
print(p.x, p.y)
# pythonic code
파이썬에서 잘쓰이는 코드 테크닉들이 있다.
많은 개발자들이 이런 스타일로 코딩하므로, 이해가 필요하다.
코드가 짧아지고 더 효율적인 경우가 많다.
split & join
list comprehension
enumerate & zip
lambda & map & reduce
generator
asterisk
# split & join
빈칸을 기준으로 리스트를 만들어서 반환한다.
split()안에 구분자를 넣어주면 구분자를 기준으로 리스트를 만들어 준다.
" ".join(리스트)를 사용하면 리스트를 띄어쓰기로 구분한 문자열로 합쳐서 반환한다.
# list comprehension
기존 list를 사용하여 다른 list를 만드는 방법
일반적으로 for + append 보다 속도가 빠르다
result = [i for i in range(10)]
case1 = ["A", "B", "C"]
case2 = ["D", "E", "A"]
result = [i+j for i in word1 for j in word2] # ["AD", "AE", "AA", "BD", "BE", "BA", "CD", "CE", "CA"]
# filter
if문을 사용하여 필터링이 가능한데, if문은 for문 뒤에 위치한다.
result = [i for i in range(10) if i % 2 == 0]
else문을 사용할 수 있는데 그럴 경우에는 if else문 전체가 for문 앞으로 이동하게 된다.
result = [i+j if not(i==j) else i for i in case1 for j in case2]
# ["AD", "AE", "BD", "BE", "BA", "CD", "CE", "CA"]
# pprint
import pprint
pprint.pprint(리스트) # 사용하면 배열이 아래로 나열되면서 이쁘게 출력된다.
# 행렬만들기
result = [[i+j for i in case1 if i!="C"] for j in case2]
# enumerate
인덱스도 함께 반환된다.
{v.lower() : i for i, v in enumerate(set_text)}
# zip
두개의 리스트 값을 병렬적으로 추출할때 사용한다.
튜플이 반환된다.
alist = ['a1', 'a2', 'a3']
blist = ['b1', 'b2', 'b3']
for a, b in zip(alist, blist)
print(a, b)
# a1 b1
# a2 b2
# a3 b3
[[a, b] for a, b in zip(alist, blist)]
# [['a1', 'b1'], ['a2', 'b2'], ['a3', 'b3']]
[c for c in zip(alist, blist)]
# [('a1', 'b1'), ('a2', 'b2'), ('a3', 'b3')]
# lambda
함수 이름 없이 함수처럼 쓸수 있는 익명 함수다
f = (lambda x, y: x+y)
f(10, 50) # 60
(lambda x, y: x+y)(10, 50) # 60
# lambda의 문제점
문법이 어렵다
테스트가 어렵다
문서화 할 수 있는 docstring 지원이 되지 않는다
코드 해석이 어렵다
# map
iterable에 각각 어떤 함수를 적용해 반환한다.
ex = [1, 2, 3, ,4 ,5]
f = lambda x: x**2
list(map(f, ex)) # [1, 4, 9, 16, 25]
f = lambda x, y: x + y
list(map(f, ex, ex)) # 람다의 파라미터가 두개일때는 파라미터를 두번 넣어 zip처럼 사용할 수 있다.
list(map(lambda x: x**2 if x%2==0 else x, ex)) # 조건문도 사용할 수 있다.
다만, 리스트 컴프리헨션을 사용하는게 더 간편한 경우가 많다.
# reduce
누산개념이 적용된다.
from functools import reduce
print(reduce(lambda x, y: x+ y, [1,2,3,4,5]))
# lambda, map, reduce
간단한 코드로 다양한 기능을 제공한다.
하지만 직관성이 떨어지기 때문에 lambda와 reduce는 파이썬3에서 사용을 지양하는 분위기이다.
다만, 레거시에서 여전히 사용중인 경우가 많다.
# iterator
내부적 구현으로 __iter__와 __next__가 사용된다.
리스트에서의 첫 주소값을 가져와 구성한다.
iterator= iter(리스트)
다음 값을 가져올때는 next함수를 사용한다.
next(iterator)
# generator
iterable object를 특수한 형태롤 사용해주는 함수이다.
요수가 사용되는 시점에 값을 메모리에 반환한다.
return 대신 yield를 사용하여 반환이 여러번 가능한 함수로, 메모리 절약이 가능하다.
데이터를 한번에 가지고 있는게 아니라, 데이터를 뽑아주는 자판기를 가지고 있는 개념이다.
# generator comprehension
generator 형태의 리스트를 만들 수 있다.
[] 대신 ()를 사용하여 표현한다.
gen_ex = (n*n for n in range(500))
# function passing arguments
1. keyword arguments
2. default arguments
3. variable-length arguments
# keyword arguments
print_somthing(your_name="TEAMLAB", my_name="sungchul")
# default arguments
함수를 선언할때 기본 값을 설정할 수 있다.
def print_somthing(my_name, your_name="TEAMLAB")
print_somthing("내이름", "TEAMLAB")
print_somthing("내이름")
# variable-length arguments(가변인자)
개수가 정해지지 않은 변수를 함수의 parameter로 사용하는 방법
keyword arguments와도 함께 사용 할 수 있다
asterisk(*)기호를 사용해서 함수의 parameter를 표시한다
입력된 값은 tuple type으로 사용할 수 있다
가변인자는 딱 한개만 마지막 parameter 위치에서 사용할 수 있다
가변인자는 일반적으로 *args를 변수명으로 사용한다
기존 parameter 이후에 나오는 값을 tuple롤 저장한다
def asterisk_test(a, b, *args):
return a+b+sum(args)
print(asterisk_text(1,2,3,4,5))
# keyword variable-length(키워드 가변인자)
파라미터 이름을 따로 지정하지 않고 입력하는 방법이다.
asterisk 두개를 사용하여 함수의 parameter를 표시한다.
입력된 값은 dict type으로 사용할 수 있다.
def kwargs_test_1(**kwargs):
print(kwargs)
kwargs_test_1(first=3, second=4, third=5)
# 복잡한 형태의 키워드 가변인자
가변인자로 파라미터를 정의하는 순서는 정해져있다.
def kwargs_test_3(one, two, *args, **kwargs):
print(one+two+sum(args))
print(kwargs)
kwargs_test_3(3, 4, 5,6,7,8,9, first=3,second=4,third=5)
# asterisk
단순곱셈, 제곱연산, 가변인자활용 등으로도 사용되지만...
unpacking container로 사용할 수 있다.
tuple, dict등 자료형에 들어가 있는 값을 unpacking한다
함수의 입력값, zip등에 유용하게 사용이 가능하다.
def asterisk_test(a, *args):
....
asterisk_test(1, *(2,3,4,5,6))
ex = ([1,2], [3,4], [5,6], [5,6], [5,6])
for value in zip(*ex):
print(value)
dict 타입에 사용할때는 **args와 같이 두번 사용한다.
def asterisk_test(a, **args):
....