摘要:約束名字空間作用域之間的那些事不管在什么編程語言都有作用域這個概念作用域控制在它范圍內代碼的生存周期包括名字和實體的綁定名字和實體的綁定我們可以理解成賦值當我們執行這句代碼時實際上我們已經得到一個的關聯關系我們也能將稱之為約束這個約束也將存
約束 名字空間 作用域 之間的那些事
不管在什么編程語言, 都有作用域這個概念.作用域控制在它范圍內代碼的生存周期, 包括名字和實體的綁定.
名字和實體的綁定, 我們可以理解成賦值. num = int_obj, 當我們執行這句代碼時, 實際上我們已經得到一個("num", int_obj)的關聯關系, 我們也能將稱之為約束, 這個約束也將存在名字空間(name space)里面, 名字空間也將是LEGB查找的依據.
而每個名字空間, 也將對應一個作用域, 作用域是代碼正文中的一段代碼區域, 作用域的有效范圍更多是這段代碼區域去衡量,一個作用域可以有多個名字空間, 一個名字空間也能有多個約束(多個賦值語句)
可以通過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
從函數的定義可以看到, sys._getframe將返回一個frameobject對象, 那其實frameobject是什么對象? 為什么它能決定作用域?
frameobjec實際上就是python虛擬機上所維護的每個棧幀, 這和我們常規理解的棧幀多點差別, 因為python在原有棧幀的基礎上, 在封裝一層形成自己的棧幀. 雖然是有些不同, 但是我們還是能近似看成常規理解的棧幀, 包括入棧,出棧 局部變量等等
那么frameobejct里面究竟有什么?
# help(sys._getframe()) # Output: class frame(object) ..... # 省略 | Data descriptors defined here: | f_back # 上一個棧幀對象(誰調用自己) | f_builtins # 內置名字空間 | f_locals # 全局名字空間 | f_globals # 全局名字空間 | f_code # 幀指向的 codeObject對象 ..... # 省略
我們現在已經知道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的名字, 通常是類名或者函數名 /* string (name, for reference) */ | | co_names # code block中所有的名字 /* list of strings (names used) */ | ...... # 省略
雖然 sys._getframe().f_code.co_name 頂多也只能說明, 這段代碼是在哪個code block里面, 并沒有直接證明就是作用域, 但是從上面也已經談到, 作用域是從代碼正文的代碼片段的決定, So, 也能近似看成算是作用域的名字了~
作用域話題似乎聊得有點深入了, 讓我們暫告一段落, 繼續講講 約束 和 作用域的關系吧
每個約束一旦創建, 將會持續的影響后面代碼的執行, 但是約束也只能在名字空間內生效, 也就是說,一旦出了名字空間/作用域. 約束也將失效
a = 3 def f(): a = 6 print a # 輸出 6 f() print a # 輸出 3
在上面例子可以看到, 變量a在模塊層和函數f層都有賦值, 在執行函數f時,輸出6, 但是在下面卻輸出了3, 也就是因為函數f 中的 a=3 約束只有在函數f的作用域中生效,函數結束,a的值, 應該是最開始的a=3來控制, 我們現在應該隱約有種感覺, 為什么賦值語句會被稱為約束? 我們完全可以理解成, 一個變量名, 可能有多次改變其綁定的實體對象的機會, 但是最終顯示是哪個實體, 完全就是從作用域->名字空間->約束 來決定
LEGB從上面我們已經清楚 約束,名字空間, 作用域之間微妙的關系, 那么我們接下來就應該探討下變量查找的方式了.
LEGB 分別是:
locals 是函數內的名字空間,包括局部變量和形參
enclosing 外部嵌套函數的名字空間(閉包中常見)
globals 全局變量,函數定義所在模塊的名字空間
builtins 內置模塊的名字空間
而查找的優先順序從左到右以此是: L -> E -> G -> B
從上面我們已經知道, 約束, 是受作用域和名字空間的影響, 所以查找肯定也是只能在名字空間去進行
來些簡單代碼吧:
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, 當在函數內部的名字空間找不到關于變量a的約束時, 將會去全局變量的名字空間查到, OK, 已經找到了 (a,3)的約束, 返回 3., test()也是同理
同樣的, 在函數內部和模塊內部都不能找到open的約束, 那么只能去Bulitin(內置名字空間)去查找了, 找到了open了, 并且還是個函數, 所以返回
簡單的演示完, 來些神奇的代碼:
a = 3 def f(): a = 4 def v(): print a return v test = f() test() # 輸出 4 Why?
有沒有覺得很奇怪, a=4是在函數f里面定義的, 但是返回v的時候, 函數已經退出,理應釋放了, 為什么test()還能輸出4呢? 其實原因很簡單, 首先這個已經是閉包函數了, 同樣的還是遵循LEGB的原則, 函數v已經能夠在外層嵌套作用域找到a的定義, 又因為閉包函數有個特點, 在構建的時候, 能夠將需要的約束也一并綁定到自身里頭, 所以即使函數f退出了, 變量a釋放了, 但是不要緊, 函數v已經綁定好了相應的約束了, 自然而然也就能輸出4
歡迎各位大神指點交流,轉載請注明: https://segmentfault.com/a/11...
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/38573.html
摘要:真正管理這些名子的事物就是本文的主角命名空間。閉包命名空間閉包函數的名稱空間引入。函數調用時產生新的局部命名空間函數返回結果拋出異常時釋放命名空間,每一次遞歸都生成一個命名空間。標識符產生地點決定標識符所處的命名空間。 懶得掃全文的童鞋,可以直接跳到最后看總結。我們先從一個簡單的栗子說起: 栗子 a 文件中有變量 va 以及類 A,b 文件導入 a 中class A ,并打印出 A: ...
摘要:理解的名字空間的名字空間是一個非常核心的內容。在中提供了一個關鍵字來修改外部嵌套函數的名字空間,但是要使用才有,我等使用的只能眼饞一下。 理解 Python 的 LEGB 名字空間 Python 的名字空間是 Python 一個非常核心的內容。 其他語言中如 C 中,變量名是內存地址的別名,而在 Python 中,名字是一個字符串對象,它與他指向的對象構成一個{name:obje...
摘要:當程序引用某個變量的名字時,就會從當前名字空間開始搜索。對于可以看出已經被導入到自己的名字空間了,而不是在里面。因此并沒有涉及到修改名字空間。按照原則,搜到有變量并且是個然后將其加入到自己的后面的就開始讀取的元素,并沒有影響的名字空間。 源自我的博客 前言 python里面最核心的內容就是:名字空間(namespace) 例子引入 例1 #!/usr/bin/env python #...
摘要:例題核心編程第二版變量作用域和命名空間一節有以下一道題目請問輸出結果是什么要想解這道題,必須先了解中的一些概念的變量名解析機制有時稱為。 例題 《核心編程(第二版)》變量作用域和命名空間一節有以下一道題目 # coding=utf-8 #!/usr/bin/env python def proc1(): j,k = 3,4 print j == %d and k ==...
摘要:在函數中執行賦值操作時,會創建一個局部變量,如果想在函數中通過賦值改變一個全局變量,則需要用關鍵字申明,只要出現了操作符,則這個變量就是局部變量,除非顯示申明為。 python變量與變量作用域 c語言中,變量的定義會為變量分配一塊內存,變量的內存地址不會發生改變,當變量的值發生改變時,改變的是對應內存地址中的值。 python中,給變量賦值時,變量保存的是一個對象的引用,如果想改變變...
閱讀 2234·2021-11-17 09:33
閱讀 2774·2021-11-12 10:36
閱讀 3396·2021-09-27 13:47
閱讀 884·2021-09-22 15:10
閱讀 3485·2021-09-09 11:51
閱讀 1392·2021-08-25 09:38
閱讀 2758·2019-08-30 15:55
閱讀 2608·2019-08-30 15:53