久久国产成人av_抖音国产毛片_a片网站免费观看_A片无码播放手机在线观看,色五月在线观看,亚洲精品m在线观看,女人自慰的免费网址,悠悠在线观看精品视频,一级日本片免费的,亚洲精品久,国产精品成人久久久久久久

分享

Python 作用域和 LEGB

 萬皇之皇 2018-02-13



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


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


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


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


可以通過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將返回一個(gè)frameobject對象, 那其實(shí)frameobject是什么對象? 為什么它能決定作用域?


frameobjec實(shí)際上就是python虛擬機(jī)上所維護(hù)的每個(gè)棧幀, 這和我們常規(guī)理解的棧幀多點(diǎn)差別, 因?yàn)閜ython在原有棧幀的基礎(chǔ)上, 在封裝一層形成自己的棧幀. 雖然是有些不同, 但是我們還是能近似看成常規(guī)理解的棧幀, 包括入棧,出棧 局部變量等等


那么frameobejct里面究竟有什么?


# help(sys._getframe())

# Output:

class frame(object)

.....            # 省略

|  Data descriptors defined here:

|  f_back        # 上一個(gè)棧幀對象(誰調(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 頂多也只能說明, 這段代碼是在哪個(gè)code block里面, 并沒有直接證明就是作用域, 但是從上面也已經(jīng)談到, 作用域是從代碼正文的代碼片段的決定, So, 也能近似看成算是作用域的名字了~


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


每個(gè)約束一旦創(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時(shí),輸出6, 但是在下面卻輸出了3, 也就是因?yàn)楹瘮?shù)f 中的 a=3 約束只有在函數(shù)f的作用域中生效,函數(shù)結(jié)束,a的值, 應(yīng)該是最開始的a=3來控制, 我們現(xiàn)在應(yīng)該隱約有種感覺, 為什么賦值語句會被稱為約束? 我們完全可以理解成, 一個(gè)變量名, 可能有多次改變其綁定的實(shí)體對象的機(jī)會, 但是最終顯示是哪個(gè)實(shí)體, 完全就是從作用域->名字空間->約束 來決定

 

LEGB


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


LEGB 分別是:


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

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

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

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


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


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


來些簡單代碼吧:


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, 當(dāng)在函數(shù)內(nèi)部的名字空間找不到關(guān)于變量a的約束時(shí), 將會去全局變量的名字空間查到, OK, 已經(jīng)找到了 (a,3)的約束, 返回 3., test()也是同理


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


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


a = 3

def f():

    a = 4

    def v():

        print a

    return v

test = f()

test()     # 輸出 4 Why?


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



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

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多