1. 程式人生 > 程式設計 >Python函數語言程式設計例項詳解

Python函數語言程式設計例項詳解

本文例項講述了Python函數語言程式設計。分享給大家供大家參考,具體如下:

函數語言程式設計就是一種抽象程度很高的程式設計正規化,從計算機硬體->組合語言->C語言->Python抽象程度越高、越貼近於計算,但執行效率也越低。純粹的函數語言程式設計語言編寫的函式沒有變數,因此,任意一個函式,只要輸入是確定的,輸出就是確定的,這種純函式我們稱之為沒有副作用。而允許使用變數的程式設計語言,由於函式內部的變數狀態不確定,同樣的輸入,可能得到不同的輸出,因此,這種函式是有副作用的。函數語言程式設計的一個特點就是,允許把函式本身作為引數傳入另一個函式,還允許返回一個函式!

Python對函數語言程式設計提供部分支援,支援高階函式(函式可以作為變數傳入),支援閉包(返回一個函式),有限地支援匿名函式。由於Python允許使用變數,因此,Python不是純函數語言程式設計語言。

1、高階函式

即可以通過變數名指向函式,函式通過變數名作為引數傳給另一個函式,並通過變數名來使用。例如下面將開方函式math.sqrt作為引數傳遞給變數f,變數名f就指向了函式math.sqrt,再通過變數f使用該函式給x、y開方。

import math
def add(x,y,f):
  return f(x) + f(y) # 函式作為引數傳遞給f來呼叫
res = add(25,9,math.sqrt)
print(res)

map函式接收一個函式 f 和一個 list,並把函式 f 依次作用在 list 的每個元素上,得到一個iterators並返回。

def format_name(s):
  return s[0].upper()+s[1:].lower()  #將列表的每個元素首字母大寫,其他小寫
print(list(map(format_name,['adam','LISA','barT'])))
#輸出:['Adam','Lisa','Bart']

filter()根據判斷函式f的結果自動過濾掉不符合條件的元素,以iterators返回剩下的元素

def is_odd(x):
  return x % 2 == 1 # 過濾函式,x為奇返回True
f_res = filter(is_odd,[1,4,6,7,12,17])
print(list(f_res))  # 輸出過濾後的結果list:1 7 9 17

sorted()函式用於對可迭代的物件進行排序,引數key=指定排序的關鍵字,這裡可以藉助functools.cmp_to_keys()將比較方法對映為自定義的方法。例如實現了降序排列,比較函式cmp返回值 -1 代表a 應該排在 b 的前面,如果a排在b 的後面返回 1。如果 a、b相等返回 0。

import functools
def cmp(a,b):
  if b < a:
    return -1
  if a < b:
    return 1
  return 0
a = [1,2,5,4]
print(sorted(a,key=functools.cmp_to_key(cmp)))

2、匿名函式和閉包

有時函式簡單到只有一個表示式時,為了簡化程式碼可以使用匿名函式來代替,匿名函式一般形式為lambda 引數:返回表示式,例如lambda x:x*x,就是傳入x引數並返回x的平方。例如在使用map()函式時需要傳入一個函式用於list的元素,此時可以使用匿名函式作為引數

lst = [1,3,8,9]
res = map(lambda x: x * x,lst)  # 將匿名函式作用於lst
print(list(res))

函式的閉包(Closure)是指內層函式引用了外層函式的變數,然後將內層函式像變數一樣返回的情況。例如函式calc_prod()接收一個list,在其內部定義一個函式multiply,計算list元素的乘積並將multiply返回。用f接收calc_prod()的返回函式,並在之後呼叫該函式

def calc_prod(lst):
  def multiply():
    res=1
    for i in lst:
      res=res*i
    return res
  return multiply  # 將函式返回
f = calc_prod([1,4])  # 接收返回函式
print(f())  # 呼叫返回函式

注意在函式閉包時要確保引用的區域性變數在函式返回後不能變。例如下面的例子,當count()函式返回3個函式時,由於f1、f2、f3並沒有被呼叫,所以並未計算 i*i。當 f1 被呼叫時,這3個函式所引用的變數 i 的值已經變成了3,所以此時使用的變數i的值已經發生了改變,三個函式的輸出都是9。

def count():
  fs = []
  for i in range(1,4):
    def f():
      print(i)  # 函式f1()呼叫時i已經變為3
      return i*i
    fs.append(f)
  return fs
f1,f2,f3 = count()
print(f1())      # 輸出9而不是1

3、函式裝飾器

函式裝飾器是指在原有函式的基礎上對函式作修改和裝飾操作。其基本思想是,既然函式可以像變數一樣作為引數傳入並且返回,那麼我們可以將原來的函式傳入裝飾器函式,然後增加我們需要的操作,之後在將原函式返回出來。

例如下面定義了一個裝飾器log用於列印函式名稱,原函式作為引數f傳入。在裝飾器中定義新的函式fn,其中引數列*args和**kw代表自適應引數個數,防止不同引數個數的函式在使用裝飾器時不匹配。在新函式fn中輸出原函式的名稱,之後將原函式原封不動地呼叫一遍並返回出去。最後返回新函式。

在使用裝飾器時,只需要在函式的定義前加一行@裝飾器名

def log(f): # 定義裝飾器log
  def fn(*args,**kw): # 定義新函式
    print('函式名: ' + f.__name__)  # 列印函式名
    return f(*args,**kw) # 在新函式中呼叫原函式並返回結果
  return fn # 返回新函式
@log # 為函式add新增裝飾器
def add(x,y):
  return x + y
print(add(1,2))

如果希望給裝飾器傳入一個引數,則需要定義三重巢狀的函式,在最外層增加一層函式用於接收引數。例如希望在列印函式名之前輸出傳入的引數“DEBUG”

def log(prefix):
  def log_decorator(f):
    def wrapper(*args,**kw):
      print '[%s] %s()...' % (prefix,f.__name__)
      return f(*args,**kw)
    return wrapper
  return log_decorator
@log('DEBUG')  # 為裝飾器傳入引數
def test():
  pass
test()

由於裝飾器實際上是建立了新的函式fn並替代了原函式,所以原函式的相關資訊例如函式名會被覆蓋,可以用@functools.wraps(f)來複制原函式的資訊以保留下來。

import functools
def log(f):
  @functools.wraps(f)
  def fn(*args,**kw):
    print 'call...'
    return f(*args,**kw)
  return fn

偏函式可以為函式填上一個固定的引數值,從而生成一個新的函式。例如原函式add需要兩個引數x、y,通過指定y=1得到偏函式add1,這個函式只需要輸入一個引數x,從而計算x+1的值。

import functools
def add(x,y):
  return x + y
add1 = functools.partial(add,y=1)
print(add2(3))  # 輸出結果為4

關於Python相關內容感興趣的讀者可檢視本站專題:《Python函式使用技巧總結》、《Python面向物件程式設計入門與進階教程》、《Python資料結構與演算法教程》、《Python字串操作技巧彙總》、《Python編碼操作技巧總結》及《Python入門與進階經典教程》

希望本文所述對大家Python程式設計有所幫助。