코드구조 6
코드구조
함수 - 데코레이터
아래와 같은 코드가 있다.
def add_num(a, b):
return a + b
r = add_num(10, 20)
print(r)
> 30
만약 함수를 출력할 때 다른 값들을 출력하고 싶다면
def add_num(a, b):
return a + b
print('start')
r = add_num(10, 20)
print('end')
print(r)
> start
end
30
물론 원하는 결과를 얻었지만 이것이 반복된다면
함수로 정의하여 사용하는 것이 효율적일 것이다.
이런것을 데코레이터라고 한다.
def print_info(func):
def wrapper(*args, **kwargs): # 인수 아무거나 가져올 수 있도록 이렇~
print('start')
result = func(*args, **kwargs)
print('end')
return result
return wrapper # 실행하지않고 오브젝트만 돌려줌
def add_num(a, b):
return a + b
f = print_info(add_num)
r = f(10, 20)
print(r)
> 30
디버거
1. f = print_info(add_num)에서 함수 호출하면
2. def print_info(func)로 가서
3. def wrapper(*args, *kwargs) 내부함수로감
4. 할 거 없으니 내부함수 return wrapper 로 감 이때 ()로 실행하지 않았으니 오브젝트만 돌려받음
5. f == wrapper됨
6. r = f(10, 20) 로감 즉 r = wrapper(10, 20) 가 됨, 4번 때문에
7. def wrapper(args, *kwargs) 바로 내부함수로 감
8. print('start') start 출력
9. result = func(args, *kwargs) 로 가고
10. func을 add_num으로 받았니까 def add_num(a, b) 로 가서 return값 받음
11. 다시 result = func(args, **kwargs) 로 와서 result = 30
12. print('end') end 출력
13. return 30
14. r = f(10, 20) 로 와서 r = 30
15. print(r) 30 출력
데코레이터를 호출 할 때 코드량을 줄이기 위해
@ 사용함
def print_info(func):
def wrapper(*args, **kwargs): # 인수 아무거나 가져올 수 있도록 이렇
print('start')
result = func(*args, **kwargs)
print('end')
return result # 실행하지않고 오브젝트만 돌려줌
return wrapper
@print_info
def add_num(a, b):
return a + b
r = add_num(10, 20)
print(r)
> start
end
30
- r = add_num(10, 20) 호출
- 바로 내부함수 def wrapper(*args, **kwargs) 로 감
- print('start') start 출력
- result = func(*args, **kwargs) 로 가고
- func을 add_num으로 받았니까 def add_num(a, b) 로 가서 return값 받음
- 다시 result = func(*args, **kwargs) 로 와서 result = 30
- print('end') end 출력
- return 30
- r = f(10, 20) 로 와서 r = 30
- print(r) 30 출력
함수 - 2, 람다
대소문자가 뒤죽박죽인 리스트가 있다.
l = ['Mon', 'tue', 'wed', 'Thu', 'fri', 'sat', 'Sun']
함수를 정의해서 대문자로 바꿔주자
def change_words(words, func):
for word in words:
print(func(word))
def sample_func(word):
return word.capitalize()
change_words(l, sample_func)
> Mon
Tue
Wed
Thu
Fri
Sat
Sun
- change_words(l, sample_func) 호출
- def change_words(words, func) 로 감
words = l = ['Mon', 'tue', 'wed', 'Thu', 'fri', 'sat', 'Sun']- for word in words 에서 word = 'Mon'
- print(func(word)) 로 가서 바로 def sample_func(word) 로 감. 현재 word: 'Mon'
- return word.capitalize() 로 가서 다시 print(func(word)) 로 감
- Mon 출력
- 다시 for 문으로 감. word : 'tue'
- 반복
이때 두번째 함수인 sample_func를 람다를 이용하여 간단하게 한줄로 쓸 수 있다.
def change_words(words, func):
for word in words:
print(func(word))
"""
# 기존
def sample_func(word):
return word.capitalize()
"""
# 람다 사용
sample_func = lambda word: word.capitalize()
change_words(l, sample_func)
> Mon
Tue
Wed
Thu
Fri
Sat
Sun
혹은 람다를 정의하지 않아도 호출시에 적어줘도 가능함(가장 best)
def change_words(words, func):
for word in words:
print(func(word))
change_words(l, lambda word: word.capitalize())
> Mon
Tue
Wed
Thu
Fri
Sat
Sun
람다로 호출하는 방식을 사용하면 함수정의가 적어져 코드량이 줄어들게 된다.
함수 - 3, 제너레이터
l = ['Good morning', 'Good afternoon', 'Good night']
for i in l:
print(i)
>Good morning
Good afternoon
Good night
for문을 돌려서 순서대로 전부 출력함
하나씩 출력하고 싶을 때 제너레이터를 사용함
def greeting():
yield 'Good morning' # 산출한다는 의미
yield 'Good afternoon'
yield 'Good night' # 제너레이터는 return이 없고 yield사용
for g in greeting():
print(g)
>Good morning
Good afternoon
Good night
return 말고 yield를 사용하는 것이 제너레이터
제너레이터(g)는 next를 이용하여 순서대로 하나씩 출력이 가능하다
g = greeting()
print('######')
print(next(g))
print(next(g))
print('######')
print(next(g))
> ######
Good morning
Good afternoon
######
Good night
데이터를 전부 킵하는게 아니라 호출할 때까지 기다렸다가 호출하면 그때 값을 줌
print(next(g))
> StopIteration
위처럼 선넘어서 한번더 실행하면(yield 초과) StopIteration 뜸
(나중에 에러처리에서 처리해야함)
Author And Source
이 문제에 관하여(코드구조 6), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@sayxyoung/python-syntax-codestructure-func6저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)