# 函數式編程
## 裝飾器 *有點面向切面的意思*
> http://python.jobbole.com/82112/
> 內置裝飾器 有:靜態方法staticmethod、類方法classmethod和類方法轉換成屬性訪問property
def log(func):
def wrapper(*args, **kw):
print 'call %s():' % func.__name__
return func(*args, **kw)
return wrapper
@log
def action():
print '2013-12-25'
#把@log放到now()函數的定義處,相當于執行了語句 now = log(now)
> **上例** 每個動作都要記錄日志;把動作函數傳入log方法 返回一個閉包 后面調用的action實際就是wrapper
### 有參數的裝飾器
def log(text):
def decorator(func):
def wrapper(*args, **kw):
print '%s %s():' % (text, func.__name__)
return func(*args, **kw)
return wrapper
return decorator
@log('execute')
def now():
print '2013-12-25'
#把@log('execute')放到now()函數的定義處,相當于執行了語句 now = log('execute')(now)
### 注意 屬性變化
> now.\_\_name\_\_ 已經變成了 wrapper
需要把 now的屬性復制到 wrapper函數中 否則依賴函數屬性(簽名)的代碼會出錯
不需要編寫wrapper.\_\_name\_\_ = func.\_\_name\_\_這樣的代碼,Python內置的functools.wraps就是干這個事的
wrapper函數上面 加上 @functools.wraps(func)
## 閉包
> **todo** 閉包的使用情景舉例
def lazy_sum(*args):
def sum():
ax = 0
for n in args:
ax = ax + n
return ax
return sum
f = lazy_sum(1, 3, 5, 7, 9)
f # <function lazy_sum.<locals>.sum at 0x101c6ed90>
f() #25 調用函數f時,才真正計算求和的結果:
> 我們在函數lazy_sum中又定義了函數sum,并且,內部函數sum可以引用外部函數lazy_sum的參數和局部變量,當lazy_sum返回函數sum時,相關參數和變量都保存在返回的函數中,這種稱為“閉包(Closure)
> 當我們調用lazy_sum()時,每次調用都會返回一個新的函數,即使傳入相同的參數
def count():
fs = []
for i in range(1, 4):
def f():
return i*i
fs.append(f)
return fs
f1, f2, f3 = count()
f1() f2() f3() # 9 9 9
#原因就在于返回的函數引用了變量i,但它并非立刻執行。等到3個函數都返回時,它們所引用的變量i已經變成了3,因此最終結果為9
def count():
def f(j):
def g():
return j*j
return g
fs = []
for i in range(1, 4):
fs.append(f(i)) # f(i)立刻被執行,因此i的當前值被傳入f()
return fs
f1() f2() f3() # 1 4 9
## 偏函數
def int2(x, base=2):
return int(x, base)
int2 = functools.partial(int, base=2) # functools.partial就是幫助我們創建一個偏函數
int2('1000000') # 64
## 高階函數
> 函數名也是變量、函數名也可以賦值給變量
> 函數名賦值常量以后 不能在調用
abs(-10) 絕對值
f = abs
f(-10)
abs = 10
abs(-10) # TypeError: 'int' object is not callable
#由于abs函數實際上是定義在import builtins模塊中的,所以要讓修改abs變量的指向在其它模塊也生效,要用import builtins; builtins.abs = 10
> 函數可以作為參數
def add(x,y,f):
return f(x) + f(y)
add(-5,6,abs) # 11
## map reduce filter sorted函數
> map 對一個迭代對象元素使用f函數 并返回新的迭代對象
list(map(str, [1, 2, 3, 4, 5, 6, 7, 8, 9]))
> reduce這個函數必須接收兩個參數,把結果繼續和序列的下一個元素做累積計算
from functools import reduce
def add(x, y):
return x + y
reduce(add, [1, 3, 5, 7, 9])
> filter 傳入的函數依次作用于每個元素,然后根據返回值是True還是False決定保留還是丟棄該元素
list(filter(is_odd, [1, 2, 4, 5, 6, 9, 10, 15])) # is_odd 只保留奇數
> sorted()函數就可以對list進行排序
sorted(['bob', 'about', 'Zoo', 'Credit'], key=str.lower, reverse=True)
## lambda x,y: x+y lambda [參數...] : 返回值