<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          Python中令人頭疼的變量作用域問題,終于弄清楚了

          共 4403字,需瀏覽 9分鐘

           ·

          2021-05-15 08:43


          來源:Python數(shù)據(jù)之道

          作者:大奎  整理:陽哥


          學(xué)習(xí)Python變量過程中,曾經(jīng)為變量混亂的作用域問題頭疼不已,全局變量、局部變量、自由變量傻傻分不清,今天來跟大家分享 Python變量作用域 的知識點(diǎn),文章內(nèi)容由公眾號讀者 大奎 創(chuàng)作。

          我們經(jīng)常聽說Python函數(shù)訪問局部變量、全局變量;在定義裝飾器的時(shí)候,還會使用自由變量。這些不同的變量是如何賦值、初始化、查找及修改的呢?各自的作用細(xì)則又是什么樣的呢?本篇嘗試解答這個問題。

          Python中的變量名可以指代變量、函數(shù)、類、對象等。一般來說,每個對象都有一個變量名指向,更準(zhǔn)確說是 綁定

          作用域的必要性

          為啥變量要有作用域呢?

          我們在Python里遇到的內(nèi)置、局部、全局及自由變量,就是說變量的作用域。

          語言區(qū)分作用域,是為了復(fù)用變量名。引入作用域,相當(dāng)于給變量劃分了各自的“隔離區(qū)”,在不同”隔離區(qū)“里,查找變量變得很容易。

          正是因?yàn)橛辛俗饔糜颍覀冊诤瘮?shù)內(nèi)才可以隨意使用變量名,而不擔(dān)心其與全局變量、其他函數(shù)中的變量沖突——因?yàn)檫@兩個作用域是分割的。

          BASIC語言只有全局變量,你能想象嗎?你在一個函數(shù)里命名的循環(huán)變量i,很可能跟全局變量沖突。寫起程序來,舉步維艱。且會導(dǎo)致很多修改、檢索問題,維護(hù)很困難。

          Python變量定義的時(shí)間和空間

          Python 有哪些作用域呢?

          Python是動態(tài)類型語言,變量是在定義的時(shí)候賦值的。這句話的意思我們分以下幾個方面來理解:

          • a = 1 賦值時(shí)定義變量
          • from tools import cubie 導(dǎo)入時(shí)定義變量 cubie
          • def fun():pass 定義函數(shù),綁定變量fun
          • def fun(name=None):pass 定義變量name為函數(shù)fun的形式變量(也是局部變量),同時(shí)定義函數(shù),綁定便令fun
          • class Car:pass  定義類,綁定類名Car

          以上,我們弄清了變量定義的時(shí)刻,下面來看變量的作用域,也就是變量的活動空間怎么規(guī)定出來的。

          變量作用域取決于其 定義位置

          • 定義在函數(shù)內(nèi)部的變量、定義在函數(shù)聲明中的形式參數(shù),視為局部變量。
          • 定義在 .py 文件內(nèi)的,且函數(shù)、類之外的變量,視為全局變量。
          • 定義在函數(shù)中,嵌套函數(shù)外,且被嵌套函數(shù)引用的變量,視為自由變量。
          • 定義在builtin中的變量,視為內(nèi)置變量。

          面對如此復(fù)雜的四種變量作用域,用一個例子來說明它們的訪問規(guī)則。

          LEGB規(guī)則

          四個作用域遵循LEGB規(guī)則,讓我們用一個例子來說明。

          import builtins

          builtins.b = 'builtins'
          g = 'global'

          def outer(o1,o2='o2'):
              e = 'enclose'
              def inner(i1,i2='i2'):
                  print(i1,i2,o1,o2,e,g,b)
              return inner 

          fun = outer('o1'
          fun('i1')

          其輸出為 i1 i2 o1 o2 enclose global builtins

          可見,在outer函數(shù)的嵌套函數(shù)inner中的輸出語句 print(i1,i2,o1,o2,e,g,b) 是本程序的重點(diǎn)。其具體執(zhí)行情況如下:

          • print i1和i2,毫無疑問的局部變量。
          • print o1和o2,本地作用域沒有,向上查找到outer函數(shù)形參。形參也為局部變量,所以該變量實(shí)際定義在outer函數(shù)內(nèi),inner這個內(nèi)嵌函數(shù)外,而inner內(nèi)部引用了這個變量,所以視為自由變量。
          • print e,本地作用域沒有,類似上例,視為自由變量。
          • print g,本地作用域沒有,自由變量作用域(閉包)沒有,一直上溯到全局作用局找到。
          • print b,本地作用域沒有,自由變量作用域(閉包)沒有,全局作用局沒有,一致上溯到內(nèi)置變量空間找到。

          至此,LEGB規(guī)則呼之欲出:在本地空間尋找不到的變量,逐級向上級尋找。這里的LEGB分別指代Local,Enclose,Global和Builtin。

          在函數(shù)中讀取賦值全局變量,在內(nèi)嵌函數(shù)中讀取賦值自由變量,會有一些不同的地方。

          nonlocal 和 global

          對變量名的賦值和引用,是兩種不同的情況:

          • 賦值:創(chuàng)建一個變量或者修改。
          • 引用:檢索其值。

          以上兩者的差別,會導(dǎo)致我們在函數(shù)中:

          • 賦值一個
            • 全局變量:等于創(chuàng)建一個局部變量。
            • 自由變量:等于創(chuàng)建一個局部變量。
          • 引用:正常檢索其值。

          我們修改上例中的inner函數(shù)為如下形式:

          def inner(i1,i2='i2'):
              e = 'enclose'
              g = 'inner global'
              print(i1,i2,o1,o2,e,g,b)

          在嵌套函數(shù)內(nèi),重新定義了g變量,其他語言一般理解這是重新賦值全局變量。但是我們看上條規(guī)則:在函數(shù)中,賦值一個全局變量時(shí),等于創(chuàng)建一個局部變量。就是說此時(shí)的g已經(jīng)是局部變量了——在程序最后的 print(g) 語句輸出 global,而不是修改后的 inner global 也驗(yàn)證了以上規(guī)則。

          完整代碼如下:

          import builtins

          builtins.b = 'builtins'
          g = 'global'

          def outer(o1,o2='o2'):
              e = 'enclose'
              g = 'inner global'
              def inner(i1,i2='i2'):
                  print(i1,i2,o1,o2,e,g,b)
              return inner 

          fun = outer('o1'
          fun('i1')

          print(g)

          輸出結(jié)果如下:

          i1 i2 o1 o2 enclose inner global builtins
          global

          不重新賦值,只是使用全局變量和自由變量,則沒有問題。

          自由變量也是類似的情況。

          為了解決局部作用域中賦值全局變量和自由變量導(dǎo)致的變成局部變量問題,Python引入關(guān)鍵字 globalnonlocal

          def inner(i1,i2='i2'):
              global g
              nonlocal e
              g = 'inner global'
              e = 'inner enclose'

          此時(shí)的賦值,則分別是對全局變量和自由變量的操作,而非新建局部變量。

          完整代碼如下:

          import builtins

          builtins.b = 'builtins'
          g = 'global'

          def outer(o1,o2='o2'):
              e = 'enclose'
              def inner(i1,i2='i2'):
                  global g
                  nonlocal e
                  g = 'inner global'
                  e = 'inner enclose'
                  print(i1,i2,o1,o2,e,g,b)
              return inner 

          fun = outer('o1'
          fun('i1')

          print(g)

          輸出結(jié)果如下:

          i1 i2 o1 o2 inner enclose inner global builtins
          inner global

          總結(jié)

          • Python的作用域分為四種,分別是局部、全局、自由和內(nèi)置;
          • 定義變量的位置決定了變量的作用域;
          • 作用域的查找遵守LEGB規(guī)則;
          • 為了在局部作用域中修改全局變量和自由變量,引入了 global 關(guān)鍵字和 nonlocal 關(guān)鍵字。

          作者簡介

          鞏慶奎,大奎,對 Python、電子信息工程感興趣,Email:[email protected]

          推薦閱讀


          Pandas處理數(shù)據(jù)太慢,來試試Polars吧!
          懶人必備!只需一行代碼,就能導(dǎo)入所有的Python庫
          絕!關(guān)于pip的15個使用小技巧
          介紹10個常用的Python內(nèi)置函數(shù),99.99%的人都在用!
          可能是全網(wǎng)最完整的 Python 操作 Excel庫總結(jié)!

          瀏覽 40
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評論
          圖片
          表情
          推薦
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  天天干天天操青青草 | 99在线精品视频观看 | 日本免费黄色视频 | 国产国内精品灰色夫妻网 | 日韩三级片在线播放 |