코드구조 6

5058 단어 pythonSyntaxTILSyntax

코드구조

함수 - 데코레이터

아래와 같은 코드가 있다.

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
  1. r = add_num(10, 20) 호출
  2. 바로 내부함수 def wrapper(*args, **kwargs) 로 감
  3. print('start') start 출력
  4. result = func(*args, **kwargs) 로 가고
  5. func을 add_num으로 받았니까 def add_num(a, b) 로 가서 return값 받음
  6. 다시 result = func(*args, **kwargs) 로 와서 result = 30
  7. print('end') end 출력
  8. return 30
  9. r = f(10, 20) 로 와서 r = 30
  10. 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
  1. change_words(l, sample_func) 호출
  2. def change_words(words, func) 로 감
    words = l = ['Mon', 'tue', 'wed', 'Thu', 'fri', 'sat', 'Sun']
  3. for word in words 에서 word = 'Mon'
  4. print(func(word)) 로 가서 바로 def sample_func(word) 로 감. 현재 word: 'Mon'
  5. return word.capitalize() 로 가서 다시 print(func(word)) 로 감
  6. Mon 출력
  7. 다시 for 문으로 감. word : 'tue'
  8. 반복

이때 두번째 함수인 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 뜸
(나중에 에러처리에서 처리해야함)

좋은 웹페이지 즐겨찾기