1. 程式人生 > 程式設計 >淺談Python 函數語言程式設計

淺談Python 函數語言程式設計

匿名函式lambda表示式

什麼是匿名函式?

匿名函式,顧名思義就是沒有名字的函式,在程式中不用使用 def 進行定義,可以直接使用 lambda 關鍵字編寫簡單的程式碼邏輯。lambda 本質上是一個函式物件,可以將其賦值給另一個變數,再由該變數來呼叫函式,也可以直接使用。

#平時,我們是先定義函式,再進行呼叫
def power(x):
  return x ** 2

print(power(2))

#使用lambda表示式的時候,我們可以這樣操作
power = lambda x : x ** 2
print(power(2))

#覺得太麻煩,還可以這樣呼叫
print((lambda x: 2 * x)(8))

lambda表示式的基本格式:lambda 入參 : 表示式

#入參可以有多個,比如 
power = lambda x,n: x ** n

print(power(2,3))

lambda 表示式的使用場景

一般適用於建立一些臨時性的,小巧的函式。比如上面的 power函式,我們當然可以使用 def 來定義,但使用 lambda 來建立會顯得很簡潔,尤其是在高階函式的使用中。

定義一個函式,傳入一個list,將list每個元素的值加1

def add(l = []):
  return [x +1 for x in l]

print(add([1,2,3]))

上面的函式改成將所有元素的值加2

可能大家會說,這還不簡單,直接把return裡的1改成2就行了。但是真的行嗎?如果函式被多個地方使用,而其他地方並不想加2,怎麼辦?

這好辦,把變得那部分抽出來,讓呼叫者自己傳

def add(func,l = []):
  return [func(x) for x in l]

def add1(x):
  return x+1

def add2(x):
  return x+2

print(add(add1,[1,3]))
print(add(add2,3]))

一個簡簡單單的問題,一定要用這麼多程式碼實現?

def add(func,l = []):
  return [func(x) for x in l]

print(add(lambda x:x+1,3]))
print(add(lambda x:x+2,3]))

map函式

map的基本格式

map(func,*iterables)

map() 函式接收兩個以上的引數,開頭一個是函式,剩下的是序列,將傳入的函式依次作用到序列的每個元素,並把結果作為新的序列返回。也就是類似 map(func,3])

同樣的,我們還是來完成這樣一個功能:將list每個元素的值加1

def add(x):
  return x + 1

result = map(add,3,4])
print(type(result))
print(list(result))

使用lambda表示式簡化操作

result = map(lambda x: x + 1,4])
print(type(result))
print(list(result))

函式中帶兩個引數的map函式格式

使用map函式,將兩個序列的資料對應位置求和,之後返回,也就是對[1,3],[4,5,6]兩個序列進行操作之後,返回結果[5,7,9]

print(list(map(lambda x,y: x + y,6])))

對於兩個序列元素個數一樣的,相對好理解。如果兩個序列個數不一樣的,會不會報錯?

print(list(map(lambda x,5])))

我們可以看到不會報錯,但是結果以個數少的為準

reduce函式

reduce函式的基本格式

reduce(function,sequence,initial=None)

reduce把一個函式作用在一個序列上,這個函式必須接收兩個引數,reduce函式把結果繼續和序列的下一個元素做累積計算,跟遞迴有點類似,reduce函式會被上一個計算結果應用到本次計算中

reduce(func,3]) = func(func(1,2),3)

使用reduce函式,計算一個列表的乘積

from functools import reduce

def func(x,y):
  return x * y

print(reduce(func,4]))

結合lambda表示式,簡化操作

from functools import reduce

print(reduce(lambda x,y: x * y,4]))

filter 函式

filter 顧名思義是過濾的意思,帶有雜質的(非需要的資料),經過 filter 處理之後,就被過濾掉。

filter函式的基本格式

filter(function_or_None,iterable)

filter() 接收一個函式和一個序列。把傳入的函式依次作用於每個元素,然後根據返回值是 True 還是 False 決定保留還是丟棄該元素。

使用 filter 函式對給定序列進行操作,最後返回序列中所有偶數

print(list(filter(lambda x: x % 2 == 0,4,5])))

sorted 函式

sorted從字面上就可以看去這是個用來排序的函式,sorted 可以對所有可迭代的物件進行排序操作

sorted的基本格式

sorted(iterable,key=None,reverse=False)

#iterable -- 可迭代物件。
#key -- 主要是用來進行比較的元素,只有一個引數,具體的函式的引數就是取自於可迭代物件中,指定可迭代物件中的一個元素來進行排序。
#reverse -- 排序規則,reverse = True 降序 , reverse = False 升序(預設)。 

#對序列做升序排序
print(sorted([1,6,9]))

#對序列做降序排序
print(sorted([1,9],reverse=True))

#對儲存多個列表的列表做排序
data = [["Python",99],["c",88]]
print(sorted(data,key=lambda item: item[1]))

閉包

在萬物皆物件的Python中,函式是否能作為函式的返回值進行返回呢?

def my_power():
  n = 2
  def power(x):
    return x ** n
  return power

p = my_power()
print(p(4))

#------------------------------------------------------------
def my_power():
  n = 2
  def power(x):
    return x ** n
  return power

n = 3
p = my_power()
print(p(4))

我們可以看到,my_power 函式在返回的時候,也將其引用的值(n)一同帶回,n 的值被新的函式所使用,這種情況我們稱之為閉包

當我們把n的值移除到my_power函式外面,這個時候來看下計算結果

n = 2

def my_power():
  def power(x):
    return x ** n
  return power

n = 3
p = my_power()
print(p(4))

為什麼輸出的結果會是64?

我們先來看看閉包時,p.__closure____的結果

#例1
def my_power():
  n = 2
  def power(x):
    return x ** n
  return power

p = my_power()
print(p.__closure__)

#結果:(<cell at 0x00000264518F9A38: int object at 0x00007FFA7F617120>)
#closure是內部函式的一個屬性,用來儲存環境變數

#---------------------------------------------------------------------

#例2
n = 2
def my_power():
  def power(x):
    return x ** n
  return power

n = 3
p = my_power()
print(p.__closure__)

#輸出結果 None

通過例1跟例2對比,我們可以知道,例2並不是閉包

閉包經典問題

下面的程式是否是閉包?能否正確執行

def my_power():
  n = 2
  
  def power(x):
    n += 1
    return x ** n
  
  return power

p = my_power()
print(p(3))

如何讓上面的程式正確執行?看看改正之後的結果

def my_power():
  n = 2
  
  def power(x):
    nonlocal n
    n += 1
    return x ** n
  
  return power

p = my_power()
print(p.__closure__)
print(p(3))
print(p(3))

看看下面的程式的執行結果

def my_power():
  n = 2
  L = []
  for i in range(1,3):
    def power():
      return i ** n
    
    L.append(power)
  return L

f1,f2 = my_power()
print(f1())
print(f2())
print(f1.__closure__[0].cell_contents)
print(f2.__closure__[0].cell_contents)

python的函式只有在執行時,才會去找函式體裡的變數的值,也就是說你連形參都不確定,你咋求知道 i為幾呢?在這裡,你只需要記住如果你連形參都不確定,python就只會記住最後一個i值。

裝飾器及其應用

什麼是裝飾器模式

裝飾器模式(Decorator Pattern)允許向一個現有的物件新增新的功能,同時又不改變其結構。這種型別的設計模式屬於結構型模式,它是作為現有的類的一個包裝。

這種模式建立了一個裝飾類,用來包裝原有的類,並在保持類方法簽名完整性的前提下,提供了額外的功能。

import time

start = time.time()
time.sleep(4)
end = time.time()
print(end - start)

從實際例子來看裝飾器

def my_fun():
  print("這是一個函式")

my_fun()

要再列印“這是一個函式”前面在列印多一行hello world。

def my_fun():
  begin = time.time()
  time.sleep(2)
  print("這裡一個函式")
  end = time.time()
  print(end-begin)

my_fun()

這個時候,如果不想修改原有的函式,咋整?

def my_fun():
  print("這是一個函式")

def my_time(func):
  begin = time.time()
  time.sleep(2)
  func()
  end = time.time()
  print(end - begin)

my_time(func)

這種方式,因為要增加功能,導致所有的業務呼叫方都得進行修改,此法明顯不可取。

另一種方式:

def print_cost(func):
  def wrapper():
    begin = time.time()
    time.sleep(2)
    func()
    end = time.time()
    print(end - begin)
    return wrapper

@print_cost
def my_fun():
  print("這裡一個函式")

第二種方式並沒有修改func函式的內部實現,而是使用裝飾器模式對其功能進行裝飾增強。

以上就是淺談Python 函數語言程式設計的詳細內容,更多關於Python 函數語言程式設計的資料請關注我們其它相關文章!