<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      剛轉行1年測試新手:學習Python編程經驗實戰分享

      一、開頭說兩句

      作為一名零基礎轉行剛一年的測試新手來說,深知自己在技術經驗方面落后太多,難免會有急于求成的心態,這也就導致自己在學習新知識時似懂非懂,剛開始學完那會還胸有成竹,一段時間之后卻又忘的一干二凈,導致我要不停回去復習,還始終不得要領,難以在實踐中靈活運用。

      相信有不少同學跟我一樣徘徊躊躇,現在老師給予了我一個給大家分享經驗的機會,我也剛好結合前段時間復習關于Python裝飾器的理解來說下,若有不對的地方,還望各位同學,同行,老師及時指出。

      二、裝飾器必知基礎

      其實很多知識點沒有牢牢掌握,是因為最最基礎的知識沒有理解透徹導致。這也是我在學習裝飾器時對于自己的評價,所以先讓我們來聊聊學習裝飾器所需要的基礎知識。

      1、形參與實參

      函數的參數分為形式參數實際參數,簡稱形參和實參。

      • 形參即在定義函數時,括號內聲明的參數。形參本質就是一個變量,用來接收外部傳來的值
      • 實參即在調用函數時,括號內傳入的值,值可以是常量,變量,表達式或三者的組合

      具體使用時又分為位置參數,關鍵字參數和默認參數

      def info(name,age,sex='male')
      	print(f'name:{name} age:{age} sex:{sex}')
      info(name='jack',18)
      

      上述示例中,調用函數時以key=value形式的就是關鍵字參數,定義函數時name,age為位置參數,sex為默認參數。

      注意

      • 調用函數時,實參可以是按位置或關鍵字的混合使用,但必須保證關鍵字參數在位置參數后面,且不可以對一個形參重復賦值
      • 默認參數的值通常應設為不可變類型

      2、可變長度參數*args和**kwargs

      參數的長度可變指的是調用函數時,實參的個數可以不固定,而在調用階段,實參無非是按照位置或者按關鍵字兩種形式,因此就出現了兩種解決方案來處理。

      2.1 可變長度的位置參數

      ? 如果在最后一個形參名前加*號,那么在調用函數時,溢出的位置實參都會被接受,以元組的形式保存下來賦值給該形參。

      def func(x,y,z=1,*args):
          print(x,y,z,args)
      func(1,2,3,4,5,6,7)
      >>1 2 3 (4,5,6,7)
      #這里起作用的就是*號,相當于溢出的位置參數賦值給了它后面的變量,即args=(4,5,6,7)
      

      2.2 可變長度的關鍵字參數

      ? 如果在最后一個形參名前加**號,那么在調用函數時,溢出的關鍵字參數,會以字典的形式保存下來賦值給形參。

      def func(x,**kwargs):
          print(x)
          print(kwargs)
      func(x=1,y=2,z=3)
      >>1
      >>{'y':2,'z':3}
      
      #同上此時相當于把溢出的關鍵字實參一,y,z都被**接收以字典的形式賦值給kwargs,即kwargs={'y':2,'z':3}
      

      2.3 組合使用

      可變參數*args與關鍵字參數kwargs通常是組合在一起使用的,如果一個函數的形參為上述兩種類型,那么代表該函數可以接收任何形式,任意長度的參數。

      def wrapper(*args,**kwargs):
          pass
      

      在該函數內部還可以把接受到的實參傳給另一個函數,這在后面推導裝飾器時大有用處。

      def func(x,y,z):
          print(x,y,z)
      def wrapper(*args,**kwargs):
          func(*args,**kwargs)
      wrapper(1,y=2,z=3)
      >>1 2 3
      

      分析

      此處在給wrapper傳參時,其遵循的事函數func的參數規則,第一步,位置參數1被接受,以元組形式保存下來賦值給args,即args=(1,),關鍵字參數y=2,z=3被**以字典形式接收賦值給kwargs,即kwargs={'y':2,'z':3};第二步,執行func(args,kwargs),即func((1,),{'y':2,'z':3}),等同于func(1,y=2,z=3)。

      3、函數對象和閉包

      函數對象指的是函數可以被當做"數據"來處理,具體可以分為四個方面的使用

      3.1 函數可以被引用

      def add(x,y):
          return x+y
      func = add
      func(1,2)
      >>3
      

      3.2 函數可以作為容器類型的元素

      dic = {'add':add}
      >>dic
      >>{'add': <function add at 0x100661e18>}
      >>dic['add'](1,2)
      >>3
      

      3.3 函數可以作為參數傳入另一個函數

      def foo(x,y,func):
          return fun(x,y)
      >>foo(1,2,add)
      >>3
      

      3.4 函數的返回值可以是一個函數

      def bdd():
          return add
      func=bdd()
      func(1,2)
      >>3
      

      3.5 閉包函數有兩個關鍵點

      • "閉":值得時函數定義在另一個函數內即內嵌函數。

      • "包":指的是該函數包含對外層函數作用于變量的引用。

        def f1():
            x = 1
            def f2():
                print(x)
        	f2()
        #此時f2就是內嵌函數,為‘閉’,f2有對外層變量x的引用,為‘包’
        #但是我們不想在內部調用f2函數該怎么辦呢
        #這個時候函數對象的引用,可以作為返回對象就可以解決,即:
        def f1():
            x = 1
            def f2():
                print(x)
        	return f2 #注意不能加括號,否者就是返回f2的執行結果,我們需要的是他的內存地址以供在外部可以隨時調用
        f = f1() #此刻變量f接受到的就是f2的內存地址
        

      總結:

      閉包函數提供了一種新的為函數體傳參的方式,為了給f2傳值,在他的同級作用域給了他一個值,f2在整體縮進,外層再給他嵌套一個函數f1包起來。此時f1從原來的全局變成了局部,為了使我們在全局依然可以調用它,通過return函數對象再返回到全局。

      三、什么是裝飾器

      上邊講了這么多,可能大家有點疑惑怎么還不介紹裝飾器。不用急,這也是我們在學習中常犯的錯誤,急于求成反而不利于對知識的吸收好消化理解。其實在潛移默化中,我們已經把大部分構成裝飾器的基本知識提到了,只是還未進行歸納整理。下面我們又將重新一步一步推導它的由來。

      定義:定義一個函數(類),該函數專門用來為其他函數(對象)添加額外的功能。

      裝飾器本質上是一個python函數或類,它可以讓其他函數或類在不需要做任何代碼修改的前提下增加額外功能,裝飾器的返回值也是一個函數/類對象。它經常用于有切面需求的場景,比如:插入日志,性能測試,事務處理,緩存,權限校驗等場景。

      四、為什么用裝飾器

      我們在為一個對象添加新功能時,往往秉持著開放封閉原則。

      • 開放:指的是對拓展功能是開放的
      • 封閉:指的是修改源代碼是封閉的

      即在不修改被裝飾對象源代碼和調用方式的情況下為被裝飾對象新增功能。有了裝飾器,我們就可以抽離出大量與函數功能本身無關的雷同代碼到裝飾器中并繼續重用。

      五、裝飾器的推導

      提出需求:為index函數新增計算代碼運行時間的功能,必須符合開放封閉原則。

      import time
      def index(x,y):
          time.sleep(2)
          print(f'來自index的{x}和{y}')
      

      1、方案一

      def index(x, y):
          start = time.time()
          time.sleep(2)
          print(f"來自index的{x}和{y}")
          stop = time.time()
          print(stop-start)
      

      結果:雖然實現了功能,但破環了開放封閉原則,修改了源代碼,不符合要求,失敗

      2、方案二

      start = time.time()
      index(1, 2)
      stop = time.time()
      print(stop-start)
      

      結果:上述代碼雖然沒有修改源代碼,也實現了功能,但是每次使用都要加上這三行代碼,太過冗余,失敗

      3、方案三

      '''在方案二的基礎上進行優化,為了解決代碼冗余,我們把它寫成一個函數'''
      def wrapper():
          start = time.time()
          index(1, 2)
          stop = time.time()
          print(stop-start)
      wrapper()
      

      結果:此時我們不用每次加上三行代碼,只需調用wrapper函數即可,但是復用性依然不夠,可以在進行優化

      4、方案四

      優化:解決index的傳參被寫死了的問題

      #此時函數參數的知識就用上了
      def wrapper(a, b):
          start = time.time()
          index(a, b)
          stop = time.time()
          print(stop-start)
      wrapper(1,2)
      #但是可能在后續的需求中index的傳參個數會發生變化
      #此時可變長度參數就能幫上大忙了
      def wrapper(*args, **kwargs):
          start = time.time()
          index(*args, **kwargs)
          stop = time.time()
          print(stop-start)
      '''這個時候就不用擔心給他傳參數的問題了,wrapper收到什么參數都會原封不動交給index函數'''
      

      結果:進行了一系列的優化,我們發現雖然傳參的問題解決了,但是這個時候index函數也寫死了,以后的需求中不可能只有它需要這個功能,復用性不夠,因此可以繼續優化

      5、方案五

      優化:index寫死了的問題

      '''我們知道一旦某個變量寫死了,那么我們就用一個變量去代替他,但是在wrapper函數中,index寫成變量后,無法通過形參傳給他,這個時候閉包函數就大顯神威了,它就提供了一種給函數傳參的方式'''
      def outter(func):
          #func = index  #寫活
          def wrapper(*args, **kwargs):
              start = time.time()
              func(*args, **kwargs)
              stop = time.time()
              print(stop-start)
          return wrapper
      f = outter(index)
      '''返回的是wrapper的內存地址賦值給f,加個括號就是在調用wrapper,它的作用就是計算以函數對象傳入其中的index的執行時間統計'''
      # 為了不改變調用方式,在進行優化
      # 可以把f = outter(index),為什么不可以賦值給index呢
      # 最后:index = outter(index) 即wrapper的內存地址
      index() # 此時對于函數的調用者來說,他沒有變化,早就換了
      

      6、方案五

      優化:上面看是已經優化得差不多了,其實還是有漏洞,原函數index是沒有返回值的,此時調用換掉之后的index之后,返回的時wrapper的內存地址,它并沒有返回值,index()返回的是None,沒有做到天衣無縫。這個時候就要用到我們上面講到的函數對象的引用可以作為返回值,問題就迎刃而解了。

      def outter(func):
          #func = index  #寫活
          def wrapper(*args, **kwargs):
              start = time.time()
              res = func(*args, **kwargs)
              stop = time.time()
              print(stop-start)
              return res
          return wrapper
      ''' 我們把func函數的返回值通過return,在返回出來,當我們運行index()時,實際上就是在調用wrapper,此刻它是有返回值的,也就是func的返回值,這個時候才做到了天衣無縫'''
      

      6、最終方案(推薦)

      def outter(func):
          def wrapper(*args, **kwargs):
              res = func(*args, **kwargs)
              return res
          return wrapper
      

      這就是一個最簡單的無參裝飾器的模版,我們想要給某個對象也就是func函數添加新功能時直接在wrapper函數內部書寫代碼即可。

      關于有參裝飾器,此處由于篇幅限制就不在說明。有參也就說明我們的函數內部需要一個參數,無非就是兩種方式,一種通過形參直接傳入,另一種就是通過閉包函數直接包給它,此處肯定是利用閉包函數更合理。

      六、感言

      誤打誤撞,因為老師的一個課后作業任務,完成了本人的第一篇知識總結。剛開始是有點驚慌的,但是隨之而來的是驚喜,雖然擔心寫的不夠好,但也算是想給自己一個交代,一個好的開始。知識的持續分享總結能夠促進我們持續的學習進步

      經過這次小小的分享,回到開頭,我想說的就是學習一些高階知識,當我們感到模模糊糊的時候,不妨回歸本質,從最基礎的原理對他進行分解,一步一步推導,往往能給到我們一種醍醐灌頂,意想不到的收獲。最后希望同大家一道能通過這次的學習,提升自己,完成自己的初心。

      ? 辛丑伊始 奮斗不止

      ? --黎潘

      posted @ 2021-04-21 09:58  狂師  閱讀(835)  評論(1)    收藏  舉報
      主站蜘蛛池模板: 久久国产热这里只有精品| 少妇无套内谢免费视频| 极品vpswindows少妇| 国产免费网站看v片元遮挡| 国产精品一区二区传媒蜜臀| 东方四虎在线观看av| 亚洲va久久久噜噜噜久久狠狠| 亚洲日韩性欧美中文字幕| 国产在线高清视频无码| 亚洲综合伊人久久大杳蕉| 九九热视频在线免费观看| 国内精品久久久久影视| 精品人妻中文无码av在线| 色老99久久精品偷偷鲁| 国产精品一区二区不卡91| 成人国产乱对白在线观看| 婷婷四虎东京热无码群交双飞视频 | 中文字幕日韩有码av| 久久青草国产精品一区| 国产a级三级三级三级| 色悠悠久久精品综合视频| 国产精品久久久福利| 午夜激情小视频一区二区| h无码精品3d动漫在线观看| 亚洲av伊人久久综合性色| 99久久激情国产精品| 99中文字幕精品国产| 岛国最新亚洲伦理成人| 999精品色在线播放| 亚洲欧美偷国产日韩| av在线播放无码线| 国产福利在线观看免费第一福利 | 无码福利写真片视频在线播放| 亚洲精品一区二区18禁| 国产一区二区三区在线观看免费| 国产自国产自愉自愉免费24区 | 国产精品色悠悠在线观看| 男女性高爱潮免费网站| 国产播放91色在线观看| 亚洲精品无码日韩国产不卡av| 屯门区|