1. 程式人生 > 其它 >多層有參裝飾器遞迴

多層有參裝飾器遞迴

多層裝飾器

  '''語法糖會將緊挨著的被裝飾物件的名字當做引數自動傳入裝飾器函式中'''
  # 判斷七局print執行順序
  def outter1(func1):
    print('載入了outter1')
    def wrapper1(*args, **kwargs):
        print('執行了wrapper1')
        res1 = func1(*args, **kwargs)
        return res1
    return wrapper1

def outter2(func2):
    print('載入了outter2')
    def wrapper2(*args, **kwargs):
        print('執行了wrapper2')
        res2 = func2(*args, **kwargs)
        return res2
    return wrapper2

def outter3(func3):
    print('載入了outter3')
    def wrapper3(*args, **kwargs):
        print('執行了wrapper3')
        res3 = func3(*args, **kwargs)
        return res3
    return wrapper3

@outter1
@outter2
@outter3
def index():
    print('from index')

有參裝飾器

  def outer(source_data):
      def login_auth(func_name):  # 不能動  只能接收一個被裝飾物件的名字
          def inner(*args, **kwargs):  # 不能動  是專門用來給被裝飾的物件傳參的
              username = input('username>>>:').strip()
              password = input('password>>>:').strip()
              # 校驗使用者資料  資料的來源可以有很多  比如全域性字典  全域性列表  文字檔案  資料庫
              # 資料的來源不同  處理方式就不同  對應的程式碼編寫就不一樣
              # 分支結構處理  然後根據不同的引數提示  匹配不同的流程
            if source_data == '1':
                print('使用字典的方式處理資料')
            elif source_data == '2':
                print('使用列表的方式處理資料')
            elif source_data == '3':
                print('使用檔案操作處理資料')
            else:
                print('其他操作情況')
            res = func_name(*args, **kwargs)
            return res
         return inner
      return  login_auth

    '''
      函式名加括號  執行優先順序最高
      @outer('3')
          左側是語法糖結構  右側是函式名加括號結構
            先執行函式呼叫  outer('3')  返回值是login_auth
            在執行語法糖結構  @login_auth
          發現最後還是一個普通的裝飾器
      有參裝飾器目的僅僅是給裝飾器傳遞額外的引數
          裝飾器最多的就三層巢狀
      並且三層巢狀的結構使用頻率不高(最多是使用別人寫好的有參裝飾器)
          from functools import wraps
          @wrps(func_name)
    '''
    @outer('3')
    def index():
        print('from index')

遞迴函式

  # 本質:遞迴函式也稱為函式的遞迴
	函式在執行過程中直接或者間接的呼叫了自身
 
  # 直接呼叫自己
   def index():
       print('from index')
       index()
   index()

  """
  maximum recursion depth exceeded while calling a Python object
  最大遞迴深度超出限制了     python直譯器自帶的應急機制

  在有些程式語言中 甚至沒有遇警機制 程式碼執行真的一致到計算機崩潰為止
  """
  # 間接呼叫自己
   def index():
       print('from index')
       func()
   def func():
       print('from func')
       index()
   func()

  """
  maximum recursion depth exceeded while calling a Python object
      這對python最大遞迴深度
          回答997 998 1000都可以
      官方給出的是1000
  """
   import sys
   print(sys.getrecursionlimit())  # 獲取預設的最大遞迴深度  # 1000
   sys.setrecursionlimit(2000)  # 還可以修改最大遞迴深度
   count = 1
   def index():
       print('from index')
       global count
       print(count)
       count += 1
       index()
   index()

  """
  函式的遞迴不應該是無限迴圈的過程 真正的遞迴函式應該要滿足兩個要求
      1.每次遞迴 複雜度必須降低(下一次遞迴要比上一次遞迴解答)
          大白話 越往下遞迴應該離解決問題的答案越近
      2.必須要有明確的結束條件
  """

  # 詮釋
  """
  需求:我想知道我們班坐在第一排的某個學生年齡
  過程:
      我問他多大了 他調皮不告訴我 說比後面那個同學大兩歲
      後面的說比他後面的大兩歲
      ...
      問到最後你一排 終於開口說 18歲
      ...
      知道最後一排的年級回推就可以知道第一排的年級
  名詞:
      遞推:一層層往下問
      回溯:根據結果推結論
  """

  # 如何編寫程式碼完成
    # 目標人物的年齡 = 後一排年齡 + 2
    # 後一排年齡 = 後後一排年齡 + 2
    # 後後一排年齡 = 後後後一排年齡 + 2
    # 後後後後一排年齡 = 18
  # 將求問年齡變成函式
       age(5) = age(4) + 2
       age(4) = age(3) + 2
       age(3) = age(2) + 2
       age(2) = age(1) + 2
       age(1) = 18
  # 封裝函式
  def get_age(n):
      if n == 1:
          return 18  # 有明確的結束條件
      return get_age(n-1) + 2
  print(get_age(4))
  '''千萬不要想複雜了 就記巢狀圖即可 有結果就是由內而外一層層撥開'''

遞迴練習

  l1 = [1,[2,[3,[4,[5,[6,[7,[8,[9,]]]]]]]]]
  '''需求:迴圈打印出列表中每一個數字'''
  # 寫程式碼之前一定要先理清思路
  """
  完整步驟 
      1.for迴圈大列表
      2.判斷元素是否是數字 如果是則列印
      3.如果不是則for迴圈
      4.判斷元素是否是數字 如果是則列印
      5.如果不是則for迴圈
      6.判斷元素是否是數字 如果是則列印
      7.如果不是則for迴圈
  ps:重複做一些事情 但是每次都比上一次簡單一些 >>>:  遞迴函式
  """
  def get_num(l):
      for i in l:  # 自帶結束條件 並且每次傳入的資料都比上一次簡單
          if isinstance(i,int):  # 判斷某個資料是否屬於某個型別
              print(i)
          else:
              get_num(i)
  get_num(l1)

演算法之二分法

  # 什麼是演算法?
	演算法其實就是解決問題的有效方法
  	eg:比如開啟易拉罐的問題
      	方法1:使用金屬撬棍
        方法2:直接手扣
        方法3:一陽指戳
        ...
  """
  演算法比較偏向於學術研究 很枯燥 並且產出很少
  甚至只有非常大的網際網路公司才會有演算法部分
  	演算法工程師薪資待遇很高 但是產出很少
  	有時候甚至幾年都沒有任何的成果 有點類似於研究所!!!
  """

# 演算法之二分法
  二分法是演算法裡面最入門的一個 主要是感受演算法的魅力所在
  """二分法使用有前提: 資料集必須有先後順序(升序 降序)"""
  l1 = [13,21,35,46,52,67,76,87,99,123,213,321,432,564,612]
  # 查詢一個數 123
  """
  二分法原理
      獲取資料集中間的元素 比對大小
          如果中間的元素大於目標資料  那麼保留資料集的左邊一半
          如果中間的元素小於目標資料  那麼保留資料集的右邊一半
      然後針對剩下的資料集再二分
          如果中間的元素大於目標資料  那麼保留資料集的左邊一半
          如果中間的元素小於目標資料  那麼保留資料集的右邊一半
      ...
    """
      def get_target(l1,target_num):
          # 最後需要考慮找不到的情況 l1不可能無限制二分
          if len(l1) == 0:
              print('不好意思 真的沒有 找不到')
              return
          # 1.獲取中間元素的索引值(只能是整數)
          middle_index = len(l1) // 2
          # 2.判斷中間索引對應的資料與目標資料的大小
          if target_num > l1[middle_index]:
              # 3.保留資料集右側
              l1_left = l1[middle_index+1:]
              # 3.1.對右側繼續二分 重複執行相同程式碼 並且複雜度降低
              print(l1_left)
              get_target(l1_left,target_num)
          elif target_num < l1[middle_index]:
              # 4.保留資料集左側
              l1_right = l1[:middle_index]
              print(l1_right)
              # 4.1.對右側繼續二分 重複執行相同程式碼 並且複雜度降低
              get_target(l1_right,target_num)
          else:
              print('找到了',target_num)
      # get_target(l1,432)
      # get_target(l1,22)
      get_target(l1,13)
  """
  二分法的缺陷
      1.如果要找的元素就在資料集的開頭 二分更加複雜
      2.資料集必須有順序
  目前沒有最完美的演算法 都有相應的限制條件
  """
  """
  以後面試的時候  可能會讓你手用python寫一些演算法
      二分法 快排 插入 冒泡 堆排序
          上述知識面試之前臨時抱佛腳即可 平時無需過多研究
  """