nested function์ ๋ฐฐ์ฐ๋ฉด์ ์๋๋ ํจ์๋ฅผ ์ ๋ฆฌํ ํฌ์คํธ์ ๋ง๋ถ์ด๋ ค๊ณ ํ๋ค. ํ์ง๋ง ๋ด์ฉ์ด ๋ ๋ฌด ๋ ๋ฌด ์ด๋ ค์์. . . ๋ฐ๋ก ๋ง๋ค์๋ค ๐คฏ
ํจ์ ์์์ ํจ์๋ฅผ ์ ์ธํ๋ ๊ฒ์ด๋ค. ์ค์ฒฉํจ์(nested function) ํน์ ๋ด๋ถ ํจ์๋ ๋ถ๋ชจ ํจ์ ์์์๋ง
ํธ์ถ ๊ฐ๋ฅํ๋ค. ๋ถ๋ชจ ํจ์๋ฅผ ๋ฒ์ด๋์ ํธ์ถ๋ ์ ์๋ค.
def parent_function():
def child_function():
print("this is a child function")
child_function()
parent_function() # result: "this is a child function"
๐ํน์ง
ํจ์ ์์ ๋ฐ๋ณต๋๋ ์ฝ๋๊ฐ ์์ผ๋ฉด ์ค์ฒฉ ํจ์๋ฅผ ์ ์ธํด ๋ถ๋ชจ ํจ์์ ์ฝ๋๋ฅผ ํจ๊ณผ์ ์ผ๋ก ๊ด๋ฆฌํ๊ณ , ๊ฐ๋ ์ฑ์ ๋์ผ ์ ์๋ค.
def print_all_elements(list_of_things):
## ์ค์ฒฉํจ์ ์ ์ธ
def print_each_element(things): # ๋ฆฌ์คํธ ์์๋ฅผ ํ๋์ฉ ๊บผ๋ด์ฃผ๋ ํจ์
for thing in things:
print(thing)
if len(list_of_things) > 0:
print_each_element(list_of_things)
else:
print("There is nothing!")
์ค์ฒฉ ํจ์๊ฐ ๋ถ๋ชจ ํจ์์ ๋ณ์๋ ์ ๋ณด๋ฅผ ๊ฐ๋์ด ์ฌ์ฉํ๋ ๊ฒ์ ์๋ฏธํ๋ค. ์ค์ฒฉ ํจ์๋ฅผ ๋ฆฌํดํ๊ธฐ ๋๋ฌธ์ ๋ถ๋ชจ ํจ์์ ๋ณ์์ ๋ฐ๋ก ์ ๊ทผ์ ๋ถ๊ฐํ๋, ์ค์ฒฉ ํจ์๋ฅผ ํตํด ์ฌ์ฉ์ ํ ์ ์๊ธฐ ๋๋ฌธ์ด๋ค.
๐ ์ฉ๋ก:
ํจ์๋ ์ค๋ธ์ ํธ๋ฅผ ์์ฑ
ํ๋ค.def generate_power(base_number):
def nth_power(power):
return base_number ** power
# ๋ถ๋ชจ ํจ์์ ๋ณ์์ธ base_number๊ฐ ์ค์ฒฉ ํจ์์ ์ฌ์ฉ๋จ (closure)
return nth_power # ์ค์ฒฉ ํจ์๊ฐ ๋ถ๋ชจ ํจ์์ ๊ฒฐ๊ณผ ๊ฐ์ผ๋ก ๋ฆฌํด
calculate_power_of_two = generate_power(2)
calculate_power_of_two(7) # base_number๊ฐ 2๋ก ์ด๋ฏธ ์
ํ
๋ ํจ์
> 128
calculate_power_of_seven = generate_power(7)
calculate_power_of_seven(3)
> 343
์ฌ์ค ๋ฐ๋ก ์ ๋ฆฌํ๊ฒ๋๊ฑด stack overflow์ ์ง์ง ์ ์ ๋ฆฌํด์ค ์ฌ๋์ด ์์ด์ ๊ฐ๋ฅํ๋ค. ๋ด์ฉ์ด ์์ฒญ ๋ง๊ณ ๊ธธ์ด์ ์ฝ์ ๋ ์ฝ๊ฐ์ ์ธ๋ด์ฌ์ด ํ์ํ๋ฐ, ๋จ๊ณ์ ์ผ๋ก ์น์ ํ๊ฒ ์ค๋ช ํด์ฃผ์ด์ ๋ฒ์ญํด๋์ผ๋ ค๊ณ ํ๋ค.
์ฐ์ ์ง๋ฌธ์ ์์์ decorator๋ฅผ ํตํด ํจ์ ๋ด์ฉ์ ํ๊ทธ<b>, <i>
๋ก ๊ฐ์ ์ ์๋์ง์ ๋ํ ๋ฌธ์ ์๋ค.
๋ฌด๋ ค 2,800์ฌ๋ฒ์ ์ถ์ฒ์ ๋ฐ์ ๋ต๊ธ๋ ์ข๊ณ , ๋ด๊ฐ ์ฎ๊ธฐ๊ณ ์๋ ๊ฐ๋ ๊น์ง ์ ๋ฆฌํด์ค ๋ต๋ณ์ ์ถ์ฒ์ด ๊ฑฐ์ 4,000์ฌ๋ฒ์ด๋ค. ๋๋ ๊ฐ๋๋ฐ์์ ์ถ์ฒํ๋ค๐ฅบ
decorator๋ ๊ฐ์ธ๋ ๊ฒ(wrappers)์ด๋ค. ํจ์ ์์ฒด๋ฅผ ๋ณ๊ฒฝ์ํค์ง ์๊ณ , decorateํ๊ณ ์ ํ๋ ํจ์์ ์ ์ด๋ ํ์ ์ฝ๋๋ฅผ ์คํํ ์ ์๋๋ก ๋ง๋ค์ด์ค๋ค.
decorator๋ฅผ ์ดํดํ๊ธฐ ์ ์, ์ฐ์ ํ์ด์ฌ์์ ํจ์๋ ๊ฐ์ฒด๋ผ๋ ์ฌ์ค์ ๊ธฐ์ตํด์ผ ํ๋ค. ํจ์๊ฐ ๊ฐ์ฒด๋ก์ ๊ธฐ๋ฅํ๋ 4๊ฐ์ง ์ฌ๋ก๋ฅผ ์ดํด๋ณด์.
def shout(word="yes"):
return word.capitalize()+"!"
print(shout()) # output 'Yes!'
scream = shout # ํจ์๋ ๊ฐ์ฒด์ด๊ธฐ ๋๋ฌธ์ ๋ณ์์ assignํ ์ ์๋ค.
print(scream()) # output: 'Yes!'
def talk():
def whisper(word="yes"): # ํจ์ ๋ด์์ ํจ์๋ฅผ ์ ์ํ ์ ์๋ค.
return word.lower()+"..."
print(whisper())
talk() # output: "yes..." whisper๋ talk ๋ฐ์ ์กด์ฌํ์ง ์์์๋ ๋ถ๊ตฌํ๊ณ ๊ฒฐ๊ณผ๊ฐ์ด ๋์จ๋ค.
def getTalk(kind="shout"):
def shout(word="yes"):
return word.capitalize()+"!"
def whisper(word="yes") :
return word.lower()+"...";
if kind == "shout":
# ํจ์๋ฅผ ํธ์ถํ๋ ๊ฒ์ด ์๋๊ธฐ ๋๋ฌธ์ ๊ดํธ๋ ์ฐ์ง ์๋๋ค.
return shout # ํจ์ ๊ฐ์ฒด๋ฅผ ๋ฆฌํดํ๋ค.
else:
return whisper
talk = getTalk()
print(talk)
#outputs : <function shout at 0xb7ea817c>
#talk ํจ์์ ๊ฐ์ฒด ์กด์ฌํ๋ค๋ ๊ฒ์ ์ ์ ์๋ค.
print(talk())
#outputs : Yes!
#()๊ดํธ๋ฅผ ๋ถ์์ผ๋ก์จ ํจ์ ๋ด์์ ์ ์ํ ํจ์๋ฅผ ํธ์ถํ๋ค.
ํจ์๋ฅผ ํ๋ผ๋ฏธํฐ๋ก์จ ๋๊ธธ ์ ์๋ค.
def doSomethingBefore(func):
print("I do something before then I call the function you gave me")
print(func())
doSomethingBefore(scream) #์์์ ์ ์ํ๋ ํจ์๋ฅผ assignํ ๋ณ์
#outputs:
#I do something before then I call the function you gave me
#Yes!
์๋์ผ๋ก ๋ง๋๋ ๋ฐฉ๋ฒ์ด๋ค. ํจ์ ์ด๋ฆ์ ๊ด๋ จ๋๊ฒ ๋ถ์ฌ์ฃผ๋๊น ๊ธธ์ด๋ ์ดํดํ๊ธฐ ์ฌ์ด ๊ฒ ๊ฐ๋ค. ๋ต๋ณ์๊ฐ ์ฃผ์์ ํตํด ๊ณผ์ ํ๋ํ๋ ์ค๋ช ํด์ฃผ์ด์ ๊ธธ์ด์ง์ง ์๋๋ก ๋ช ๋ฌธ์ฅ๋ง ์ง์ฐ๊ณ ๋ณ์ญํ์๋ค.
# decorator๋ ๋ค๋ฅธ ํจ์๋ฅผ ํ๋ผ๋ฏธํฐ๋ก์ ๋ฐ๋ ํจ์์ด๋ค.
def my_shiny_new_decorator(a_function_to_decorate):
# decorator ์ ์ชฝ ๋ค์ด์ค๋ฉด ๋ฐ๋ก ๊ฐ์ธ๋ ํจ์(wrapper)๋ฅผ ์ ์ํ๋ค. ์ด ํจ์๋ original ํจ์๋ฅผ ๊ฐ์ธ์ original ํจ์์ ์ ํ์ ์ฝ๋๋ฅผ ์คํํ ๊ฒ์ด๋ค.
def the_wrapper_around_the_original_function():
# original ํจ์ ์ ์ ์คํ๋ ์ฝ๋๋ฅผ ๋ฃ๋๋ค.
print("Before the function runs")
# original ํจ์๋ฅผ ํธ์ถํ๋ค.
a_function_to_decorate()
# # original ํจ์ ํ์ ์คํ๋ ์ฝ๋๋ฅผ ๋ฃ๋๋ค.
print("After the function runs")
# ์ด ์์ ์์, "a_function_to_decorate"๋ ์์ง๊น์ง ์คํ๋ ์ ์ด ์๋ค. ์ ์๋ ํจ์ ๋ด์ ์กด์ฌํ ๋ฟ์ด๋ค. ๊ทธ๋ฆฌ๊ณ wrapper ํจ์(ํจ์์ ์ฝ๋๋ค์ ๊ฐ๊ณ ์๋)๋ฅผ returnํด ์ฌ์ฉํ ์ค๋น๊ฐ ์๋ฃ๋ ์ํ๋ก ๋ง๋ ๋ค.
return the_wrapper_around_the_original_function
# ๊ทธ๋ฆฌ๊ณ ๋ค์๋ ๋ง์ง๊ณ ์ถ์ง ์์ ํจ์๋ฅผ ๋ง๋ค์๋ค๊ณ ์์ํ์.
def a_stand_alone_function():
print("I am a stand alone function, don't you dare modify me")
# ํด๋น ํจ์์ ํ๋ ๋ฒ์๋ฅผ ํ์ฅํ๊ธฐ ์ํด decorate๋ฅผ ํ ์ ์๋ค. ๊ทธ๋ฅ decorator์ ํจ์๋ฅผ passํ๋ฉด ๋๋ค.
a_stand_alone_function_decorated = my_shiny_new_decorator(a_stand_alone_function)
a_stand_alone_function_decorated()
#outputs:
#Before the function runs
#I am a stand alone function, don't you dare modify me
#After the function runs
#์๋ decorator๋ฅผ ํต๊ณผํ ํจ์๋ฅผ ๋ณ์์ assignํ ๊ฒ์ด๊ณ , ์๋์ ๊ฐ์ด ๋งค๋ฒ decorator์ ํจ๊ป ๋์ํ๋ ํจ์๋ฅผ ๋ง๋ค ์๋ ์๋ค.
a_stand_alone_function = my_shiny_new_decorator(a_stand_alone_function)
a_stand_alone_function()
๊ทธ๋ฌ๋๊น decorator๋ ๋ด๊ฐ ๊ฐ๊ณ ์๋ ํจ์๋ฅผ ๊ฐ์ธ์ค ์ ์๊ณ , ํจ์๋ฅผ decorator์ pass๋ง ํ๋ฉด ๋ด ํจ์๊ฐ ๋ค๋ฅธ ๋ชจ์ต์ ๊ฐ์ง ์ ์๋๊ฑฐ๋ค. ์์ฒญ๋๊ฒ ๊ธธ์ง๋ง ์ดํดํ๊ธฐ ์ฝ๋ค.
decorator syntax๋ฅผ ํตํด ์ฌ๋ฌ ํจ์์ ์์ ์์ฌ๋ก ๋ถ์ผ ์๋ ์๋ค. decorator ์ด๋ฆ ์์ @๋ฅผ ๋ถ์ฌ์ ์ด๋ค.
@my_shiny_new_decorator
def another_stand_alone_function():
print("Leave me alone")
another_stand_alone_function()
#outputs:
#Before the function runs
#Leave me alone
#After the function runs
๋ต๋ณ์๊ฐ ํน์ ๊ธฐํธ๋ก ํ๋ฒ๊ฑฐ๋ฅผ ๋ง๋๋ decorator๋ฅผ ๋ง๋ค์๋ค. ๋ ๊ท์ฝ๊ธฐ๋ ํ๊ณ wrapper๋ผ๋ ๊ฐ๋ ์ ๋ณด๋ค ์ ์๋ฟ์ ์ ์๊ฒ ๋ง๋ ๊ฒ ๊ฐ๋ค. (๋๋ํ๊ณ ์ผ์ค์์ด..)
def bread(func):
def wrapper():
print("</''''''\>")
func()
print("<\______/>")
return wrapper
def ingredients(func):
def wrapper():
print("#tomatoes#")
func()
print("~salad~")
return wrapper
@bread
@ingredients
def sandwich(food="--ham--"):
print(food)
sandwich()
#outputs:
#</''''''\>
# #tomatoes#
# --ham--
# ~salad~
#<\______/>
๊ทธ๋์ ๋ด๊ฐ ๊ณผ์ ํ๋ฉด์ ์ฒ์์ผ๋ก ์ ์ผ ์ด๋ ต๋ค๊ณ ๋๋ ๋ฌธ์ ๊ฐ ... ์๋ ์กฐ๊ฑด์์ ํจ์๋ฅผ ์คํํ๋ฉด "Hello, ์๋"๊ฐ ๋์ค๋๋ก decorator๋ฅผ ๋ง๋๋ ๊ฒ์ด์๋ค.
@name_decorator("์๋")
def greeting():
return "Hello, "
greeting()
์ ๊ณ์ ํค๋งธ๋๋ฉด, ๋ณดํต python decorator๋ฅผ ๊ตฌ๊ธ๋งํ ๊ฒฝ์ฐ decorator์ ํ๋ผ๋ฏธํฐ๋ก original function์ด ๋ค์ด๊ฐ๋ค. stack overflow ์น์ ํ ๋ต๋ณ์์ ์์์ฒ๋ผ ํ๋ผ๋ฏธํฐ์ ๋ด๊ฐ decorateํ๊ณ ์ ํ๋ ํจ์๊ฐ ๋ค์ด๊ฐ๊ณ , ํจ์ ์์๋๋ก wrapper๊ฐ(๋๋ถ๋ถ print๋ก ์ด๋ค์ง ์ฝ๋) ๊ฐ์ธ๋๋ก ์์๋ฅผ ๋ ๊ฒ ๋๋ถ๋ถ์ด๋ค.
๊ทผ๋ฐ ๋ฌธ์ ์์๋ decorator ํ๋ผ๋ฏธํฐ๊ฐ ๋ณ์์ ๋ฐ๋๋ค. ๊ทธ๋ฆฌ๊ณ ์ฌ์ง์ด ํจ์ ์์๋๋ก ์ฝ๋๋ฅผ ์ถ๊ฐํ๋ ๊ฒ๋ ์๋๊ณ ๊ธฐ์กด ํจ์์ ๊ธ์๋ฅผ ์ถ๊ฐํ๋ ๊ฒ๋ ๋ฌธ์ ๋ค. ๊ทธ๋์ ์ฒ์์๋ wrapper์ ์ธ์๋ฅผ ๋ฃ์ด์ผ๋๋์ค ์๊ณ ์์ฒญ ํค๋งธ๋ค.
๋ง์ฝ wrapper์ parameter๋ฅผ ๋ฃ๊ฒ ๋๋ฉด ๋ด๊ฐ decorator๋ก ๊ฐ์ธ๋ ํจ์์ ๋ณ์๋ฅผ ๋ฃ์ ์ ์๊ฒ ๋๋ค. ๊ธฐ๋ถ์ ๋ฐ๋ผ ๋ฌด์ธ๊ฐ๋ฅผ ์ฃผ๋ ํจ์๋ฅผ ๋ง๋ค์ด๋ณด์๋ค.
def my_deco(someone, feeling): # decorator์ ๋ฃ์ ๋ณ์
def inner_deco(func): # decorator๋ก ๊ฐ์ ํจ์๋ฅผ ์ ์
def wrapper(sth): # ๊ฐ์ธ์ง๋ ํจ์์ parameter๋ฅผ ์ถ๊ฐํ๋๋ก ๋ง๋ ๋ค.
func(sth)
print(f'because {someone} looks {feeling}')
return wrapper
return inner_deco
@my_deco('yeeun', 'sad')
def giver(sth): # ๋ง์ฝ wrapper์์ parameter๋ฅผ ๋ฃ์ง ์์ผ๋ฉด error๊ฐ ๋ฌ๋ค
print(f'give {sth}')
my_deco('flower')
#result:
#give flower
#because yeeun looks sad
๋ค์ ๋์์์, ์ด๋ฆ์ ๋ฃ์ด์ ํจ์๋ฅผ ํธ์ถํ๋ ค๋ฉดname_decorator(name)
๊น์ง๋ ๋ถ๋ช
ํ ๋ง๋๋ฐ, ์์๋ค์์๋ ๋ค ํจ์๋ฅผ ๋ฃ๊ณ , ๋๋์ฒด ์ name์ ์ด๋์ ๋ฃ์ด์ผํ ์ง ๋ชจ๋ฅด๊ฒ ๋๊ฑฐ๋ค... ๐ญ
์๊ณ ๋ณด๋ ์์์ decorator๋ฅผ ๋ ๋ง๋ค์ด์ผ ํ๋๊ฑฐ์๋ค. ํจ์๋ ํธ์ถํด์ผ๋๋๋ฐ ๋ฃ์ด์ผ ํ๋๊น, ์ค์ฒฉ ํจ์๋ฅผ ์ด๊ฑฐ๋ค.
๊ทธ๋๊น ๋๋ฒ ์ค์ฒฉ๋ ํจ์๋ฅผ ๋ง๋ค์ด์ผ ํ๋ ๊ฒ์ด๊ณ , ํจ์์ ์ด๋ฆ์ ๋ํ ๋๋ ๊ทธ๋ฅ printํ๊ฑฐ๋ returnํ๋๊ฒ ์๋๋ผ ๊ฐ์ฒด๋ฅผ ๋ง๋ค์ด ๋ด์์ด์ผ ํ๋ค. ์ด๋ป๊ฒ ๊ฐ์ ๋ด์์ง ๋ชจ๋ฅด๊ฒ ์ผ๋ฉด ๋น ์๋ฃ๊ตฌ์กฐ๋ฅผ ๋ง๋ค์ด์ ๋ฃ๊ฑฐ๋ ๋ณ์๋ฅผ ์๋ก ๋ง๋ค์ด ํฉ์น๋ ๊ฒ์ด ํญ์ ๋ต์ด ๋๋ ๊ฒ ๊ฐ๋ค.
def name_decorator(name):
def decorator(func):
def wrapper():
result = func()+name
return result
return wrapper
return decorator
@name_decorator("์๋")
def greeting():
return "Hello, "
greeting() #output: "Hello, "์๋"