여전히 교육은 진행중이고 여전히 블로그 정리는 계속됩니다.
오늘 강의는 이해는 되는데 어려웠습니다.
오히려 재밌는 것들을 많이 알려주셔서 집중은 더 잘됐습니다.
앞으로 할 수 있는 것들과 추천하는 형태의 코드들과 비추천 하는 형태의 코드들을
상세히 알려주셨습니다. 저도 한번 잘 정리해보려고 합니다.
클로저
함수 내 함수가 외부 변수를 참조하여 보존하는 것을 클로저 라고 합니다.
# 클로징 되어야 하는 변수에 접근하는 것을 클로저
def outer_function(x):
def inner_function(y):
return x + y
return inner_function
inner = outer_function(100)
inner(200) # inner 입장에서 100을 변경할 수 있는 방법이 없습니다.
def make_counter():
count = 0
def counter():
nonlocal count # 밖에 있는 count를 가져오겠다는 뜻
count += 1
return count
return counter
counter_a = make_counter()
print(counter_a()) # 1
print(counter_a()) # 2
print(counter_a()) # 3
이렇게 함으로 순서는 항상 상승된다고 보장할 수 있습니다. DB에서 게시물 번호 등에 쓰입니다.
security 개념으로 쓰이진 않습니다.
# 어떠한 변수를 보호하기 위한 용도로는 잘 사용하지 않습니다.
# 아래와 같이 사용하면 문제가 발생할 수도 있습니다.
def 은행(원금):
def 입금(입금금액):
return 원금 + 입금금액
return 입금
통장_입금함수 = 은행(1000) # 1000만원을 초기에 입금
통장_입금함수(100)
통장_입금함수(-1100)
요즘 은행에서 이런 시큐어 코딩 문제로 문제가 발생되는 경우는 극히 드뭅니다.
이더리움 <- 음수가 없습니다. 양수만 있습니다.
0원에서 -1원 한다. => 옛날 차 계기판 => 나올 수 있는 최댓값 => 은행 통장 잔고 전체
마이너스 연산을 허락하지 않았는데 어떻게 마이너스 연산을 한 것인까요?
해커가 인자로 인스턴스를 넣어서 마이너스 연산되도록 만들어서 해킹이 가능하다고 합니다.
대단하죠?
데코레이터
기본적으로 함수 또는 메서드를 꾸며주는 함수 데코레이터는 고차함수입니다.
일급함수는 함수를 값으로 취급 하는 것.
고차함수는 함수를 아규먼트로 사용할 수 있고, 함수를 리턴할 수 있는 함수입니다.
# 데코레이터는 함수가 호출되었을 때 실제 실행되는 함수입니다.
# 데코레이터의 return 함수가 실행되는 것입니다.
def simple_decorator(function):
def wrapper():
print("전")
function()
print("후")
return wrapper
@simple_decorator
def hello():
print("Hello, World!")
hello()
hello()
는 데코레이터가 없는 상태에서는 simple_decorator(hello)()
와 같습니다.
데코레이터 만드는 순서를 정리해주셨습니다.
# 제가 사용하는 데코레이터
# step 0
sum([1, 2, '3', 4, 5, '6']) # error! 그런데 이게 되게 하고 싶음
# step 1 : 골격을 만듭니다.
def data_pre(function):
def wrapper():
return None
return wrapper
@ data_pre
def mean(l):
return sum(l) / len(l)
mean([1, 2, '3', 4, 5, '6']) # dara_pre(mean)()
# step 2 : 파라미터를 설정합니다.
# 얻어가야할 포인트(데코레이터와는 관련이 없습니다.) : map은 __len__이 없어서 len() 안됩니다.
# 포인트2: list 형변환은 부담이 있는 연산이닌 주의를 해주세요.
def data_pre(function):
def wrapper(iter_obj):
return function(list(map(int, iter_obj)))
return wrapper
@ data_pre
def mean(l):
return sum(l) / len(l)
mean([1, 2, '3', 4, 5, '6']) # dara_pre(mean)(iter_obj) # iter_obj 에 [1, 2, '3', 4, 5, '6']
# 이 3.5는 실제 mean 반환값인가요? 실제는 wrapper에 반환값입니다.
# 좀 더 정교한 작업이 필요할 때
def data_pre(function):
def wrapper(iter_obj):
l = []
for i in iter_obj:
if isinstance(i, str):
s = ''
for j in i:
if j.isdigit():
s += j
l.append(int(s))
else:
l.append(i)
return function(list(map(int, l)))
return wrapper
@ data_pre
def mean(l):
return sum(l) / len(l)
mean([1, 2, 'l3l', 4, 5, 'abc6def']) # dara_pre(mean)(iter_obj) # iter_obj 에 [1, 2, '3', 4, 5, '6']
# 이 3.5는 실제 mean 반환값인가요? 실제는 wrapper에 반환값입니다.
강사님이 추천하시는 형태입니다.^^ 정규표현식을 배우면 훨씬 더 간단해지지만 정규표현식을 사용하지 않고,
만든 코드입니다. re.sub('[a-zA-Z]+', '')
이렇게 사용할 수 있다고 합니다. 나중에 배우겠지요?
lambda
numbers = [1, 2, 3, 4, 5]
print(list(filter(lambda x: x > 3, numbers))) # 출력: [4, 5]
def f(x):
return x > 3
numbers = [1, 2, 3, 4, 5]
print(list(filter(f, numbers))) # 출력: [4, 5]
재사용 여부에 따라 lambda를 사용할지 def 사용할지 판단하시면 됩니다.
args, kwargs
애스터리스크(*)
1개는 튜플이나 리스트를 패킹, 언패킹하는데 사용하며 2개는 딕셔너리를 패킹, 언패킹 하는데 사용됩니다.
아규먼츠(args)는 튜플 형식으로 아규먼트를 받는 반면 키워드 아규먼츠(kwargs)는 딕셔너리 형태로 아규먼트를 받습니다.
# 패킹
# *r가 패킹에 쓰였습니다.
def func(*args):
print(args)
func(10, 20, 30)
# 10, 20, 30 => *args => (10, 20, 30)
# 언패킹
# 언패킹 실무에서 자주 사용하진 않음. 패킹을 자주 사용함.
def func(a, b, c):
print(a, b, c)
args = (10, 20, 30)
func(*args) # * 안해주면 error 가 납니다. 넘겨야할 아규먼트가 3개여야 error가 안남.
# (10, 20, 30) => *args => 10, 20, 30
def f(a, b, c, d, e):
print(a, b, c, d, e)
f(1, 2, e=3, d=4, c=5) # 이렇게 보장해주는 언어가 별로 없어요. 출력 : 1 2 5 4 3
def f(*args, **kargs): # 가변적으로 parameter를 받고 싶을 때 이 형태를 많이 사용합니다.
print(args) # 출력 : (1, 2)
print(kargs) # 출력 : {'e': 3, 'd': 4, 'c': 5}
f(1, 2, e=3, d=4, c=5)
one, two, *three = 1, 2, 3, 4, 5
print(one, two, three) # 출력 : 1 2 [3, 4, 5]
a, b, *c = 'hello world'
c # 출력: ['l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd']
유용하게 사용할 수 있을 것 같습니다.
이터레이터 와 제너레이터
이터레이터란, 값을 차례대로 꺼낼 수 있는 객체
시퀀스형 자료형이란? index가 있고, indexing, slicing이 가능한 자료형
dict는 이터레이터인가요? Yes
dict는 시퀀스형 자료형인가요? No{'one': 1, 'two': 2}[2:] # error
제너레이터는 이터레이터를 만드는 함수
for i in {'one': 1, 'two': 2}:
print(i)
list(map(lambda x: x[0], {'one': 1, 'two': 2}))
결과는
one
two
['o', 't']
class MyIterator:
def __init__(self, stop):
self.current_value = 0 # 현재 값
self.stop = stop # 순회를 멈출 값
def __iter__(self):
return self
def __next__(self):
if self.current_value >= self.stop:
raise StopIteration
result = self.current_value
self.current_value += 1
return result
my_iterator = MyIterator(5)
for i in my_iterator:
print(i)
for i in my_iterator:
print(i)
전에도 배웠지만 for문은 __iter__
함수를 처음 호출하고, __next__
함수를 호출하게 됩니다.
그래서 첫 for문은 0, 1, 2, 3, 4 를 차례로 출력하지만 아래 for문은 바로 stopIteration 으로 멈춥니다.
다시 순회를 하려면 __iter__
함수에 current_value = 0
으로 초기화 하는게 필요합니다.
위의 클래스에서는 __init__
에만 쓰였습니다.
def my_generator():
x = 10
yield x
x = 20
yield x
x = 30
yield x
return
x = 40
yield x
for i in my_generator():
print(i)
제너레이터는 이터레이터를 생성해주는 함수로, yield 키워드를 사용하여 만듭니다.
def my_generator():
x = 0
while True:
yield x
x += 2
list(zip('hello', my_generator())) # 결과 : [('h', 0), ('e', 2), ('l', 4), ('l', 6), ('o', 8)]
def my_generator():
l = ['짝', '홀']
while True:
# := 왈러스 연산자(python 3.8버전)
yield l[t := False] l[False]
yield l[t := True] l[True]
list(zip([0, 1, 2, 3, 4, 5, 6], my_generator()))
결과는 [(0, '짝'), (1, '홀'), (2, '짝'), (3, '홀'), (4, '짝'), (5, '홀'), (6, '짝')]
입니다.
왈러스 연산자를 배웠었다는데 기억이 안납니다.^^
nonlocal
nonlocal은 파이썬의 키워드 중 하나로, 중첩 함수 내부에서 바깥 함수의 변수를 참조할 수 있게 합니다.
nonlocal은 주로 클로저(closure)에서 변수의 값을 변경하고자 할 때 사용합니다.
# nonlocal
a = 10
def f():
a = 100
print(f'f a: {a}')
def ff():
a = 1000
print(f'ff a: {a}')
def fff():
nonlocal a # global a로 변경해보세요.
a = 100
print(f'fff a: {a}')
fff()
print(f'ff a: {a}')
ff()
f()
print(f'global a: {a}')
nonlocal 은 바로 바깥에서 참조할 변수를 찾습니다. 없으면 다음, 없으면 다음 순서대로 찾고,
마지막에 전역변수 까지 찾습니다.
모듈
모듈이란 클래스나 함수, 변수를 다른 파일(.py)에 작성하여 다른 파이썬 코드에서 재사용할 수 있도록 한 것입니다.
# 제대로 알고 사용해야 합니다.
# 1번 스탭 : info.py를 생성
# name = 'honggildong'
# age = 10
#
# def hello():
# print('안녕하세요 저는 홍길동 입니다.')
위의 과정이 끝나면
import info as q # info.py 를 가져오겠다! info라는 이름 대신 q
q.name
q.age
q.hello()
이렇게 사용할 수 있습니다.
# 문제가 있는 코드
# 뒤에 로드 된 것이 덮어 씁니다.
# 이런 경우는 아주 극히 드물지만 일어나는 일입니다.
from info import name, age, hello
from infotwo import name
print(name)
이렇게 될 수도 있다고 하네요. 주의해서 사용해야 할 것 같습니다.
뒤에 로드 된 것이 덮어 쓴다고 합니다.
카카오 로그인, 구글 로그인, 엑셀 로드, 문자를 보내거나 하는 것들은 다 모듈로 나와 있다고 합니다.
직접 코드를 짜기 전 라이브러리가 있는지 확인할 필요가 있다고 합니다.
파이썬은 라이브러리, 프레임웤, 서드파티가 정말 잘 되어 있습니다.
라이브러리: 여러분들 코드에 라이브러리가 섞여 들어가는 코드. 예를 들어 크롤링에 request, bs4
프레임웤 : 설계 도면이 정해져 있어서 이 설계 도면대로 코딩을 해야 하는 경우,
레고 설계 도면처럼 완성품에 설계도면이 존재합니다.
서드파티 : 프레임웤에 붙는 코드. 예를 들어 Django 서드파티라고 하면 Django 로그인, DRF, Django-cors
Django 에 사용하는 서드파트만 잘 알아둬도 개발하는데 문제가 없음
collection
import collections # 알고리즘 문제에서 많이 나옴.
# deque문제: 페이지 교체 알고리즘, 회전 초밥 등 다양한 문제에서 활용됩니다.
d = collections.deque([1, 2, 3, 4])
d.rotate(1) # 1번 오른쪽으로 쉬프트 합니다. 숫자를 2로 바꾸어 비교해보세요.
d # 출력: deque([4, 1, 2, 3])
d = collections.deque([1, 2, 3, 4])
d.rotate(2) # 1번 오른쪽으로 쉬프트 합니다. 숫자를 2로 바꾸어 비교해보세요.
d # 출력: deque([4, 1, 2, 3])
c = collections.Counter('hello world')
c # 출력: Counter({'h': 1, 'e': 1, 'l': 3, 'o': 2, ' ': 1, 'w': 1, 'r': 1, 'd': 1})
c.most_common()
# 출력:
'''
[('l', 3),
('o', 2),
('h', 1),
('e', 1),
(' ', 1),
('w', 1),
('r', 1),
('d', 1)]
'''
그외 다양한 데이터 처리 하는 방법, Json 처리하는 방법 등을 배웠습니다.
다음에 또 배운다고 하니 그때 다시 정리해보겠습니다.
예외처리
try:
# s = 1/0
l = []
l.appnd(10)
print(s)
except ZeroDivisionError:
print('0으로 나누어졌습니다!')
except AttributeError:
print('메서드 없어요!')
except:
print('오류가 났습니다!')
오류가 날만한 곳에 사용합니다. 명시적으로 할수도 있지만 무슨 에러가 날지 모르잖아요.
except: 하는게 좋지 않을까 싶습니다.^^
'''
게시물 5개 쓰는 코드
'''
assert 게시물.count() == 'hello', '에러 체크 하기 위해 이렇게 많이 사용함
assert 는 에러 체크하기 위해 많이 사용한다고 합니다.
여기까지 정리하도록 하겠습니다. 많이 배우기도 했고, 어렵기도 했습니다.
과제하는데도 헷갈려서 고생을 좀 했습니다. 찾아보면서 하지 않으면 어렵습니다.
앞으로 좋은 코드를 많이 만나봐야 할 것 같습니다.
힘들고, 어렵지만... 그래도 화이팅 입니다.
'오름캠프(23.12.28 ~ 24.4.18)' 카테고리의 다른 글
오름캠프 학습일지(2024/01/19) - 4주차 5일 (0) | 2024.01.19 |
---|---|
오름캠프 학습일지(2024/01/18) - 4주차 4일 (0) | 2024.01.18 |
오름캠프 학습일지(2024/01/16) - 4주차 2일 (0) | 2024.01.16 |
오름캠프 학습일지(2024/01/15) - 4주차 1일 (1) | 2024.01.15 |
오름캠프 학습일지(2024/01/12) - 3주차 5일 (1) | 2024.01.12 |