2014年5月14日 星期三

Python-Decorate

最近用python寫作業常常看到Decorator,到底Decorator是啥?於是上網找資料才發現是跟design pattern有關

最近工作幫同事debug突然有種design pattern實在是太重要的感覺,尤其是對於大的project更是如此,難怪最近常常聽到討論某某framework如何如何的聲音,基本上framework就是基於design pattern來實現的一種架構,方便給"程序員"來維護程式。看到Python decorator一開始也是一頭霧水,這是啥?不過上網找資料後看到一句話瞬間恍然大悟

裝飾器只是裝飾器模式的python實現

先不管python裡面decorator的符號,到底裝飾器模式是在做啥?學design pattern最一開始要問的事情就是:"這種pattern的好處在哪裡?",所以decorator的好處在哪?參考下方的例子

假設hello_world.py的程式裡面有1個hello_world的function

def helloWorld_1():
   print "hello World: 1"

helloWorld_1()
output:
hello World: 1

如果今天想要改寫helloWorld_1,在print前面加上一行print "I say:"

def helloWorld_1():
   print "I say:"
   print "hello World: 1"

helloWorld_1()

很輕鬆的我們只需要加上一行就可以了,可是很不幸的如果有100隻helloWorld的function,我們都想要在前面加上print "I say:"要怎麼解決?很簡單就複製100次麻!這時問題來了,如果我們複製print "I say:"100次,結果哪天不爽想改寫成print "yo~"怎麼辦,我們就要傻傻地把100個print "I say:"改寫print"yo~",一不小心很容易漏改,所以這時decorator就出現啦!我們希望只改寫一個function就所有的helloWorld function都改寫,減少修改的overhead,decorator的design pattern就可以辦到這件事情,我們將程式改寫如下

def decorator(func):
   print "I say:"
   func()

def helloWorld_1():
   print "hello World: 1"

decorator(helloWorld_1)

output:

I say:
hello World: 1

好吧!必需承認看不出威力所在,假設今天增加為5個hello world如下

如果沒用decorator的話會呈現

def helloWorld_1():
   print "I say:"
   print "hello World: 1"

def helloWorld_2():
   print "I say:"
   print "hello World: 2"

def helloWorld_3():
   print "I say:"
   print "hello World: 3"

def helloWorld_4():
   print "I say:"
   print "hello World: 4"

def helloWorld_5(): 
   print "I say:"
   print "hello World: 5"

helloWorld_1()
helloWorld_2()
helloWorld_3()
helloWorld_4()
helloWorld_5()

用了decorator後會呈現

def decorator(func):
   print "I say:"
   func()


def helloWorld_1():
   print "hello World: 1"

def helloWorld_2():
   print "hello World: 2"

def helloWorld_3():
   print "hello World: 3"

def helloWorld_4():
   print "hello World: 4"

def helloWorld_5():
   print "hello World: 5"

decorator(helloWorld_1)
decorator(helloWorld_2)
decorator(helloWorld_3)
decorator(helloWorld_4)
decorator(helloWorld_5)

output:

I say:
hello World: 1
I say:
hello World: 2
I say:
hello World: 3
I say:
hello World: 4
I say:
hello World: 5

在這短短的程式碼中隱隱約約可以看到decorator不會動到hello world function,如果今天想把I say改成"yo~"decorator只需要修改decorator這個function即可,不用每個hello world都去修改,很明顯的如果不用decorator的話就會GG~每個hello world都要去修改

def decorator(func):
   print "yo~"
   func()


def helloWorld_1():
   print "hello World: 1"

def helloWorld_2():
   print "hello World: 2"

def helloWorld_3():
   print "hello World: 3"

def helloWorld_4():
   print "hello World: 4"

def helloWorld_5():
   print "hello World: 5"

decorator(helloWorld_1)
decorator(helloWorld_2)
decorator(helloWorld_3)
decorator(helloWorld_4)
decorator(helloWorld_5)

output:

yo~
hello World: 1
yo~
hello World: 2
yo~
hello World: 3
yo~
hello World: 4
yo~
hello World: 5

python實現decorator可以不用python提供的識別字"@",不過有提供當然有它的好處,可以參考Charming Python: Decorators make magic easy,所以上面的decorator也可以寫成下面的樣子

def decorator(func):
   print "yo~"
   func()


@decorator
def helloWorld_1():
   print "hello World: 1"

@decorator
def helloWorld_2():
   print "hello World: 2"

@decorator
def helloWorld_3():
   print "hello World: 3"

@decorator
def helloWorld_4():
   print "hello World: 4"

@decorator
def helloWorld_5():
   print "hello World: 5"

helloWorld_1
helloWorld_2
helloWorld_3
helloWorld_4
helloWorld_5

Reference:

沒有留言:

張貼留言