乡下人产国偷v产偷v自拍,国产午夜片在线观看,婷婷成人亚洲综合国产麻豆,久久综合给合久久狠狠狠9

  • <output id="e9wm2"></output>
    <s id="e9wm2"><nobr id="e9wm2"><ins id="e9wm2"></ins></nobr></s>

    • 分享

      Python 作用域和 LEGB

       萬皇之皇 2018-02-13



      約束 名字空間 作用域 之間的那些事


      不管在什么編程語言, 都有作用域這個概念.作用域控制在它范圍內(nèi)代碼的生存周期, 包括名字和實體的綁定.


      名字和實體的綁定, 我們可以理解成賦值. num = int_obj, 當我們執(zhí)行這句代碼時, 實際上我們已經(jīng)得到一個(‘num’, int_obj)的關聯(lián)關系, 我們也能將稱之為約束, 這個約束也將存在名字空間(name space)里面, 名字空間也將是LEGB查找的依據(jù).


      而每個名字空間, 也將對應一個作用域, 作用域是代碼正文中的一段代碼區(qū)域, 作用域的有效范圍更多是這段代碼區(qū)域去衡量,一個作用域可以有多個名字空間, 一個名字空間也能有多個約束(多個賦值語句)


      可以通過sys._getframe().f_code.co_name 查看代碼所處的作用域, 先來看下sys._getframe是什么鬼吧?


      # sys module

      def _getframe(depth=None): # real signature unknown; restored from __doc__

          '''

          _getframe([depth]) -> frameobject

          

          Return a frame object from the call stack.  If optional integer depth is

          given, return the frame object that many calls below the top of the stack.

          If that is deeper than the call stack, ValueError is raised.  The default

          for depth is zero, returning the frame at the top of the call stack.

          

          This function should be used for internal and specialized

          purposes only.

          '''

          pass


      從函數(shù)的定義可以看到, sys._getframe將返回一個frameobject對象, 那其實frameobject是什么對象? 為什么它能決定作用域?


      frameobjec實際上就是python虛擬機上所維護的每個棧幀, 這和我們常規(guī)理解的棧幀多點差別, 因為python在原有棧幀的基礎上, 在封裝一層形成自己的棧幀. 雖然是有些不同, 但是我們還是能近似看成常規(guī)理解的棧幀, 包括入棧,出棧 局部變量等等


      那么frameobejct里面究竟有什么?


      # help(sys._getframe())

      # Output:

      class frame(object)

      .....            # 省略

      |  Data descriptors defined here:

      |  f_back        # 上一個棧幀對象(誰調(diào)用自己)

      |  f_builtins    # 內(nèi)置名字空間

      |  f_locals      # 全局名字空間

      |  f_globals     # 全局名字空間

      |  f_code        # 幀指向的 codeObject對象

      .....            # 省略


      我們現(xiàn)在已經(jīng)知道frameobject的來歷呢, 那么再回顧上面提到的: sys._getframe().f_code.co_name


      毫無疑問, 我們還是得看下codeobject是什么東西, 才能知道name的意思:


      同樣也是print help大法


      # print help(sys._getframe().f_code)

      # Output:

      class code(object)

      ......        # 省略

      |  Data descriptors defined here:

      |  

      |  co_name    # code block的名字, 通常是類名或者函數(shù)名 /* string (name, for reference) */

      |  

      |  co_names   # code block中所有的名字 /* list of strings (names used) */

      |

      ......        # 省略


      雖然 sys._getframe().f_code.co_name 頂多也只能說明, 這段代碼是在哪個code block里面, 并沒有直接證明就是作用域, 但是從上面也已經(jīng)談到, 作用域是從代碼正文的代碼片段的決定, So, 也能近似看成算是作用域的名字了~


      作用域話題似乎聊得有點深入了, 讓我們暫告一段落, 繼續(xù)講講 約束 和 作用域的關系吧


      每個約束一旦創(chuàng)建, 將會持續(xù)的影響后面代碼的執(zhí)行, 但是約束也只能在名字空間內(nèi)生效, 也就是說,一旦出了名字空間/作用域. 約束也將失效


      a = 3

      def f():

          a = 6

          print a    # 輸出 6

      f()

      print a        # 輸出 3


      在上面例子可以看到, 變量a在模塊層和函數(shù)f層都有賦值, 在執(zhí)行函數(shù)f時,輸出6, 但是在下面卻輸出了3, 也就是因為函數(shù)f 中的 a=3 約束只有在函數(shù)f的作用域中生效,函數(shù)結束,a的值, 應該是最開始的a=3來控制, 我們現(xiàn)在應該隱約有種感覺, 為什么賦值語句會被稱為約束? 我們完全可以理解成, 一個變量名, 可能有多次改變其綁定的實體對象的機會, 但是最終顯示是哪個實體, 完全就是從作用域->名字空間->約束 來決定

       

      LEGB


      從上面我們已經(jīng)清楚 約束,名字空間, 作用域之間微妙的關系, 那么我們接下來就應該探討下變量查找的方式了.


      LEGB 分別是:


      • locals 是函數(shù)內(nèi)的名字空間,包括局部變量和形參

      • enclosing 外部嵌套函數(shù)的名字空間(閉包中常見)

      • globals 全局變量,函數(shù)定義所在模塊的名字空間

      • builtins 內(nèi)置模塊的名字空間


      而查找的優(yōu)先順序從左到右以此是: L -> E -> G -> B


      從上面我們已經(jīng)知道, 約束, 是受作用域和名字空間的影響, 所以查找肯定也是只能在名字空間去進行


      來些簡單代碼吧:


      a = 3

      def f():

          print a     # 輸出 3

          print open  # 輸出

      f()

       

      print '----------------------分割線----------------'

       

      a = 3

      def f():

          def v():

              print a

          return v

      test = f()

      test()          # 輸出 3


      這段相信大家都知道為什么能夠輸出3, 當在函數(shù)內(nèi)部的名字空間找不到關于變量a的約束時, 將會去全局變量的名字空間查到, OK, 已經(jīng)找到了 (a,3)的約束, 返回 3., test()也是同理


      同樣的, 在函數(shù)內(nèi)部和模塊內(nèi)部都不能找到open的約束, 那么只能去Bulitin(內(nèi)置名字空間)去查找了, 找到了open了, 并且還是個函數(shù), 所以返回


      簡單的演示完, 來些神奇的代碼:


      a = 3

      def f():

          a = 4

          def v():

              print a

          return v

      test = f()

      test()     # 輸出 4 Why?


      有沒有覺得很奇怪, a=4是在函數(shù)f里面定義的, 但是返回v的時候, 函數(shù)已經(jīng)退出,理應釋放了, 為什么test()還能輸出4呢? 其實原因很簡單, 首先這個已經(jīng)是閉包函數(shù)了, 同樣的還是遵循LEGB的原則, 函數(shù)v已經(jīng)能夠在外層嵌套作用域找到a的定義, 又因為閉包函數(shù)有個特點, 在構建的時候, 能夠?qū)⑿枰募s束也一并綁定到自身里頭, 所以即使函數(shù)f退出了, 變量a釋放了, 但是不要緊, 函數(shù)v已經(jīng)綁定好了相應的約束了, 自然而然也就能輸出4。



        本站是提供個人知識管理的網(wǎng)絡存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式、誘導購買等信息,謹防詐騙。如發(fā)現(xiàn)有害或侵權內(nèi)容,請點擊一鍵舉報。
        轉(zhuǎn)藏 分享 獻花(0

        0條評論

        發(fā)表

        請遵守用戶 評論公約

        類似文章 更多