python遞歸-三元表達式-列表生成式-字典生成式-匿名函數-部分內置函數-04

  • 2019 年 10 月 7 日
  • 筆記

遞歸

遞歸: # 函數在調用階段直接或間接地又調用了自身

應用場景: # 將列表中的數字依次列印出來(循環的層數是你必須要考慮的點)   –>  l = [1, [2, [3, [4, [5, [6, [7, [8, [9, [10, [11, [12, [13, ]]]]]]]]]]]]]

# 循環的寫法, 列表嵌套越多層越麻煩  for i in l:  # 推導思路      if type(i) is int:          print(i)      else:          for item in i:              if type(item) is int:                  print(item)              else:                  for j in item:                      if type(item) is int:                          print(item)                      else:                          ...  # 函數體的頂用方式(還有一是前面提到過的pass,推薦還是使用 pass來頂替,比較明目)                          # 下方嵌套多級循環,往裡面取到更下一層列表中的元素      # 遞歸的寫法,程式碼體簡短,不需要考慮循環次數  def get_num(l):      for i in l:          if type(i) is int:              print(i, end=' - ')          else:              get_num(i)      get_num(l)  # 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - 12 - 13 - 

遞歸的優點: 遞歸函數不要考慮循環的次數 只需要把握結束的條件即可

遞歸的兩個階段

  回溯:# 從外向里一層一層遞歸調用下去,回溯階段必須要有一個明確的結束條件,每進入下一次遞歸時,問題的規模都應該有所減少(單純地重複調用自身是毫無意義的)

  遞推: # 遞推就是從裡向外一層一層結束遞歸

遞歸案例:

def index():      print('from index')      login()    def login():      print('from login')      index()    login()  # ..........................此處省略一大堆報錯............................................  # File "E:/PyCharm 2019.1.3/ProjectFile/day010/day012/01 函數遞歸.py", line 120, in index  #     print('from index')  # RecursionError: maximum recursion depth exceeded while calling a Python object  # 意思是超出了最大遞歸限數

從上述案例中可得知 python解釋限制了遞歸的深度(不然就是無限循環下去,直到你的記憶體溢出,然後。。。emmm)

那麼下面我們就來測試一下 python解釋器中的遞歸深度

# 1.暴力測試 --> 997、998左右  count = 0  def index():      global count      print(count)      count += 1      index()      index()  # .....此處省略報錯  # 997  # 最後列印的數字是 997,意味著 python解釋器的遞歸深度約為997    # 2.getrecursionlimit  import sys  print(sys.getrecursionlimit())  # 不是很精確  # 1000

那麼如何修改默認的遞歸深度呢?

# 修改遞歸深度限制  import sys  sys.setrecursionlimit(1100)

應用場景2(有序列表中元素的二分法查找)

# 拋去 成員運算 in 可以直接返回元素在不在列表中,下面探究遞歸運用  # 歧義命名 l_find,  #   這裡的 l_find 代表「列表查找」,可能會與下面的往右分割列表查找,往左分割存在歧義  #   所以命名規範里的見名知意也要注意,避免引起歧義  l = [1, 2, 3, 4, 5, 6, 7, 8, 9]  # 默認約定輸入的必須是數字(亂輸的咱就不考慮在內了)  find_num = int(input("請輸入您要查找的數字>>>:").strip())      def l_find(find_num, l):      # print(l) # 可以列印中間步驟      mid_index = len(l) // 2      if not l:  # 如果是空列表了,說明該元素不在列表裡          return False      # 如果目標元素大於中間元素,那就說明元素在右邊      if find_num > l[mid_index]:          # 利用列表的切片知識,將列表切割成一個新的列表,用於遞歸繼續查找          tmp_l = l[mid_index + 1:]          res = l_find(find_num, tmp_l)      elif find_num == l[mid_index]:          # print("get it", find_num)          return True      # 如果目標元素小於中間元素,那就說明元素在左邊      else:          tmp_l = l[0:mid_index]          res = l_find(find_num, tmp_l)      return res      is_exits = l_find(find_num, l)  if is_exits:      print(f"您所要查找的數字{find_num} 在列表l 中。")  else:      print(f"您所要查找的數字{find_num} 不在列表l 中。")  # 請輸入您要查找的數字>>>:9  # 您所要查找的數字9 在列表l 中。

演算法: 解決問題的高效率的方法(不僅僅局限於數學運算)

三元表達式

先來看這樣一段程式碼

# 比較兩個數的大小  def my_max(x,y):      if x > y:          return x      else:          return y

三元表達式實現: res = x if x > y else y ,短短一行就實現了上面函數的功能

三元表達式固定格式: 值1 if 條件 else 值2 ,如果條件成立,返回 值1 ,不成立返回 值2

常見應用場景: 在編程的時候請盡量避免使用三元表達式嵌套,想要知道結果要去推算,不夠直接

is_free = input("請輸入是否免費(y/n)>>>:")  is_free = '免費' if is_free == 'y' else '收費'  print(is_free)  # 請輸入是否免費(y/n)>>>:n  # 收費

列表生成式(知識點理解可能有誤)

需求: 給列表中的除了 macbook的名字都加個馬甲 new_ –> new_tank

# 給列表中的除了 macbook的名字都加個馬甲 new_ --> new_tank  (macbook被刪掉了這點忽略)  # for循環實現  staff = ['tank', 'nick', 'oscar', 'sean', 'macbook']  staff2 = []  for people in staff:      if people != 'macbook':          staff2.append("new_%s" %people)  print(staff2)  # ['new_tank', 'new_nick', 'new_oscar', 'new_sean']      # 列表表達式實現  staff = ['tank', 'nick', 'oscar', 'sean', 'macbook']  print(['new_%s' %name for name in staff if name != "macbook"])  # macbook 不滿足條件,所以被濾過了  # ['new_tank', 'new_nick', 'new_oscar', 'new_sean']  # print(['new_' + name for name in staff if name != "macbook"])  # 跟上條語句一樣的執行效果,不過python對推薦字元串直接相加的拼接方式,它的效率十分的低!應盡量避免使用!      # 三元表達式結合列表表達式實現  staff = ['tank', 'nick', 'oscar', 'sean', 'macbook']  print([f'new_{name}' if name != 'macbook' else name for name in staff])  # ['new_tank', 'new_nick', 'new_oscar', 'new_sean', 'macbook']

  可見列表生成式只用了一行就實現了。

列表生成式原理(if後面可以不寫)

'''  先for循環依次取出列表裡面的元素      然後交由 if 判斷, 條件成立才會把元素交給for 前面的程式碼      如果當前條件不成立, 當前元素直接捨棄          不支援再加else 的情況(for 有 else , if 也有 else  會造成衝突)  '''

字典生成式

需求:將 l1 = ['name', 'age', 'hobby'] , l2 = ['jason', 18, 'DBJ'] 兩個列表分別作為鍵值組成一個字典

l1 = ['name', 'age', 'hobby']  l2 = ['jason', 18, 'DBJ']    # for 循環利用字典特性生成字典  d = {}  for i in range(len(l1)):      d[l1[i]] = l2[i]  print(d)  # {'name': 'jason', 'age': 18, 'hobby': 'DBJ'}    # 利用內置函數 zip,將 l1與l2 組合成元組,然後利用內置函數dict強轉成字典  d1 = dict(zip(l1, l2))  print(d1, zip(l1, l2))  # {'name': 'jason', 'age': 18, 'hobby': 'DBJ'} <zip object at 0x00000248171F21C8>    # d2 將l1 與 l2 中的各元素分別作為鍵值組成一個新的字典,過濾掉 age 這一個鍵值   ---> 字典生成式  d2 = {k: v for k, v in zip(l1, l2) if k != 'age'}  print(d1, d2)  # {'name': 'jason', 'age': 18, 'hobby': 'DBJ'} {'name': 'jason', 'hobby': 'DBJ'}

集合生成式也可以同理推導出來(沒有元組生成器) — > 列表生成器、字典生成器可能還有描述有誤具體還要學到後面才知道。

生成器表達式的意義: 用來創建其他任何類型的序列,增加程式碼可讀性一定程度上可以更高效

列表生成式與三元表達式結合小案例

hello_list = ['halo', 'hi', 'nice to meet you']    hello_list2 = [f"↑{item}" for item in hello_list if len(item) < 10]  print(hello_list2)  # ['↑halo', '↑hi']    hello_list3 = [f"↑{item}" if len(item) < 10 else item for item in hello_list]  # 利用三元表達式實現不同處理  print(hello_list3)  # ['↑halo', '↑hi', 'nice to meet you']

匿名函數

匿名函數: 沒有名字的函數

特點: 臨時存在,調用完立即銷毀

關鍵字: lambda

案例:

print(lambda x, y: x + y)  # <function <lambda> at 0x000001DAC45B2E18>  print((lambda x, y: x + y)(1, 3))  # 4    # :左邊的相當於函數的形參  # :右邊的相當於函數的返回值  # 匿名函數通常不會單獨使用,正常情況下是配合內置函數(也可以是自己寫的函數)一起使用的

內置函數(部分)

python3.6 中的內置函數

max 求最大值、min 求最小值

# 字典值比較  d = {      'egon': 30000,      'jason': 88888888888,      'nick': 3000,      'tank': 1000  }  print(max(d, key=lambda name: d[name]))  # 比較薪資 返回人名  print(min(d, key=lambda name: d[name]))    # key(函數的第二個關鍵字參數)那裡返回什麼,他就比較什麼,最後返回的還是for 循環到的

map 並行遍歷(可接收一個自定義函數)

# map 映射  l = [1, 2, 3, 4, 5, 6]  print(list(map(lambda x: x + 5, l)))  # 基於for循環  # [6, 7, 8, 9, 10, 11]

zip 並行遍歷

# zip 拉鏈  # 基於for循環  l1 = [1, 2, ]  l2 = ['jason', 'egon', 'tank']  l3 = ['a', 'b', 'c']  print(list(zip(l1, l2, l3)))  # [(1, 'jason', 'a'), (2, 'egon', 'b')]

filter 過濾

# filter 過濾  l = [1, 2, 3, 4, 5, 6]  print(list(filter(lambda x: x != 3, l)))  # 基於for循環  # [1, 2, 4, 5, 6]

sorted 排序

# sorted排序  l = ['jason', 'egon', 'nick', 'tank']  print(sorted(l, reverse=True))  # ['tank', 'nick', 'jason', 'egon']

reduce 合併(可指定初值)

from functools import reduce  l = [1, 2, 3, 4, 5, 6]  print(reduce(lambda x, y: x + y, l, 19))  # 19初始值  第一個參數  # 40  # 當初始值不存在的情況下 按照下面的規律  #   第一次先獲取兩個元素 相加  #   之後每次獲取一個與上一次相加的結果再相加