好程式設計師Python教程系列遞迴函式與匿名函式呼叫

好程式設計師發表於2020-04-30

  好程式設計師 Python 教程 系列遞迴函式與匿名函式呼叫 函式是Python技術學習中重要的一個環節,深入掌握該階段的知識內容,對於Python技術能力的提升非常有幫助,這裡就針對遞迴函式與匿名函式兩種函式呼叫進行系統的介紹分析。

. 遞迴函式

  a) 引言:在一個函式中自己呼叫自己會怎麼樣呢?會陷入無限的呼叫迴圈。為了解決該問題就需要使用遞迴。

  b) 應用:

  i. 案例分析:編寫一個函式,該函式接收一個整數n,然後計算輸出n的階乘。

  1. 首先定義一個一個函式def factorial(n),該函式應該怎麼實現呢?我們知道計算n的階乘有如下規律:n!=n*[(n-1)*[n-2]…*1]=n*(n-1)!

  2. 函式實現步驟可以是:

  def factorial(n):

  1.計算(n-1)的階乘

  2.返回step1的結果值*n

  要完成第一步的事情,就是要計算(n-1)!。由於我們這個函式是計算n!,因此第一步也可以理解為,以n-1為引數,呼叫factorial函式。程式碼就會變成:

  def factorial(n):

  1.factorial(n-1)

  2.返回step1的結果值*n

  在該程式碼中,出現了在factorial函式中呼叫factorial函式的情況。出現了函式的遞迴。為了完善上述程式碼,可以將程式碼中的第二部也翻譯成程式碼:

  def factorial(n):

  1. int result=factorial(n-1)

  2. return result*n

  但是問題也出現了,加入n=3,在fac(3)的內部會呼叫fac(2),在fac(2)中會呼叫fac(1),在fac(1)中會呼叫fac(0)-》fac(-1)……因此我們需要規定一個迴圈呼叫結束的條件。在當前程式中當引數n的值為1時,則計算1的階乘,到這一步就沒有必要繼續遞迴下去的必要了,因此n=1是,應當直接返回。

  def factorial(n):

  if(n==1):

  return 1

  int result=factorial(n-1)

  return result*n

. 匿名函式

  a) 引言:當我們在建立函式的時,有的時候不需要顯示的定義函式,直接傳入匿名函式會更加的方便,這會省去我們挖空心思為函式命名的麻煩,也能少些不少的程式碼,很多程式語言都提供匿名函式這種特性。匿名函式用好了,會起到畫龍點睛的效果,沒用好就容易畫虎不成反類犬,

  b) 在Python中使用lambda關鍵字來建立匿名函式。所謂匿名,即不再使用def這種標準形式定義函式,需要注意的有:

  i. lambda是一個表示式而不是一個程式碼塊

  ii. 僅僅能在lambda表示式中封裝有限的邏輯

  iii. Lambda函式擁有自己的名稱空間

  c) 語法結構:lambda 引數:表示式 例如 lambda x:x*x, 冒號前的x表示的是引數,後面的表示函式的執行程式碼,,它相當於下面的函式:

  Def f(x): return x*x

  d) 注意:

  i. 匿名函式只能有一個表示式

  ii. 不用也不能寫return語句,表示式的結果就是返回值

  iii. 匿名函式也是一個函式物件,可以將其賦值給一個變數,然後透過變數來呼叫該函式。f=lambda x:x*x f(6)

. 推導式: 是一種獨特的推導式語法,可幫我們在某些場合寫出比較精簡炫酷的程式碼。但是沒有它,也不會有太多的影響。

  a) 分類:

  i. 列表推導式

  ii. 字典推導式

  iii. 集合推導式

  iv. 元組推導式?

  b) 列表推導式:是一種快速生成列表的方式,其形式使用方括號括起來的一段語句。

  i. 案例:lis=[x*x for x in range(1,10) ] 首先執行for迴圈,對於每一個x帶入x*x中進行運算,將運算的結果值逐一新增到一個新的列表內(x*x的式子中使用的變數必須為for中的x)。尤其可見,列表推導式為我們提供了一種在一行內實現較為複雜邏輯的生成列表的方法。其核心語法就是用中括號將生成的邏輯封裝起來。

  ii. 案例:[x*x for x in range(1,11) if x%2==0] 透過增加if語句對x進行過濾

  iii. 案例:dic={“k1”:”v1”,”k2”:”v2”} a=[k+”:”+v for k,v in dic.items()]

  c) 字典推導式:列表推導式使用的是中括號,那麼如果使用大括號則可以製造字典推導式

  i. 案例:dic={x:x*2 for x in(2,4,6)} x:x*2中間的冒號左邊表示key右邊表示value

  ii. 案例:也可以新增if子句

  d) 集合推導式:大括號除了可以用作字典推導式還可以用作集合推導式,注意兩者差別。

  i. 案例:a={x for x in “abcdefg” if x not in “abc”}

  e) 元組推導式:那是用小括號的是不是元組推導式呢?no。在python中使用小括號的被叫做生成器的語法,在python中沒有元組推導式。

  i. 如果想透過上述類似的方法生成元組,需要顯示呼叫元組的型別轉換函式tuple。t=tuple(x for x in range(10))

  f) 面試題:

  result = [lambda x: x + i for i in range(10)]

  print(result[0](10))

  答案是19,並且result[0~9](10)的結果都是19。這是因為函式具有呼叫時才查詢變數的特性。在你沒呼叫它之前,它不會儲存也不關心它內部變數的具體值。只有等到你呼叫它的時候,它才逐一去找這些變數的具體值。這裡的result[0]被呼叫的時候,變數i已經迴圈完畢,變成9了,而不是想象中的動態0-9值。

  那如果不想要這樣的結果,想要i是迴圈的值怎麼辦?不要直接引用上層變數,把變數直接傳進來。

  result = [lambda x, i=i: x + i for i in range(10)]

  print(result[0](10))

. 迭代器

  a) 迭代:透過for迴圈遍歷物件的每一個元素的過程。For可以遍歷任何可迭代的物件。

  b) 可迭代物件型別:list/tuple/string/dict/set/bytes。可以透過collections模組的Iterable型別來判斷一個物件是否可迭代:

  from collections import Iterable

  isinstance('abc', Iterable) # str是否可迭代

  c) 迭代器:是一種可以被遍歷的物件。特點如下:

  i. 能呼叫next()函式。

  ii. 使用iter()函式建立迭代器物件

  iii. 迭代器物件從集合的第一個元素開始訪問,直到所有元素被訪問結束

  iv. 只能往後遍歷,不能回溯

  v. 案例:

  >>> lis=[1,2,3,4]

  >>> it = iter(lis) # 使用Python內建的iter()方法建立迭代器物件

  >>> next(it) # 使用next()方法獲取迭代器的下一個元素

  1

  >>> next(it)

  2

  >>> next(it)

  3

  >>> next(it)

  4

  >>> next(it) # 當後面沒有元素可以next的時候,彈出錯誤

  或者使用for迴圈遍歷迭代器:

  lis = [1,2,3,4]

  it = iter(lis) # 建立迭代器物件

  for x in it: # 使用for迴圈遍歷迭代物件

  print (x, end=" ")

  迭代器的作用:除了可迭代的型別可以進行迭代外,在開發中也會遇到一些自定義的型別也有迭代的需求,即將自定義型別定義成迭代器型別即可(需要在類裡實現__iter__()和__next__()方法,可供next和iter函式呼叫該物件)。for迴圈本質上就是透過不斷呼叫next()函式實現的

  def iter(obj):

  return obj.__iter__()

  def next(obj):

  return obj.__next__()

  自定義迭代器類:

  import random

  class demo_iterator(object):

  def __next__(self):

  v = random.randint(0,10)

  if v < 5:

  raise StopIteration()

  else:

  return v

  def __iter__(self):

  return demo_iterator()

  迭代作用:可以把這個元素流看做是一個有序序列,但卻不能提前知道序列的長度,只能不斷透過next()函式得到下一個元素,所以迭代器可以節省記憶體和空間。

. 生成器

  a) 引言:有時候,序列或集合內的元素的個數非常巨大,如果全製造出來並放入記憶體,對計算機的壓力是非常大的。比如,假設需要獲取一個10**20次方如此巨大的資料序列,把每一個數都生成出來,並放在一個記憶體的列表內,這是粗暴的方式,有如此大的記憶體麼?如果元素可以按照某種演算法推算出來,需要就計算到哪個,就可以在迴圈的過程中不斷推算出後續的元素,而不必建立完整的元素集合,從而節省大量的空間。在Python中,這種一邊迴圈一邊計算出元素的機制,稱為生成器:generator。

  b) 語法格式:類似推導式,使用小括號

  c) 案例:

  >>> g = (x * x for x in range(1, 4))

  >>> g

  at 0x1022ef630>

  可以透過next()函式獲得generator的下一個返回值,這點和迭代器非常相似:

  >>> next(g)

  1

  但更多情況下,我們使用for迴圈。

  for i in g:

  print(i)

  d) 關鍵字yield:

  1. 用法:使用yield返回的函式會變成一個生成器。在呼叫生成器的過程中,每次遇到yield時,函式會暫停並儲存當前所有的執行資訊,返回yeild值。並在下一次執行next方法時從當前位置繼續執行。


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69913864/viewspace-2689511/,如需轉載,請註明出處,否則將追究法律責任。

相關文章