国产片侵犯亲女视频播放_亚洲精品二区_在线免费国产视频_欧美精品一区二区三区在线_少妇久久久_在线观看av不卡

腳本之家,腳本語言編程技術及教程分享平臺!
分類導航

Python|VBS|Ruby|Lua|perl|VBA|Golang|PowerShell|Erlang|autoit|Dos|bat|

服務器之家 - 腳本之家 - Python - Python新手在作用域方面經常容易碰到的問題

Python新手在作用域方面經常容易碰到的問題

2020-05-29 11:24Amir Rachum Python

這篇文章主要介紹了Python新手在作用域方面經常容易碰到的問題,全局變量和局部變量方面的知識在Python學習當中是基礎中的基礎,需要的朋友可以參考下

通常,當我們定義了一個全局變量(好吧,我這樣說是因為講解的需要——全局變量是不好的),我們用一個函數訪問它們是能被Python理解的:
 

?
1
2
3
bar = 42
def foo():
  print bar

在這里,我們在foo函數里使用了全局變量bar,然后它也如預想的能夠正常運行:
 

?
1
2
>>> foo()
42

這樣做很酷。通常,我們在使用了這個特性之后就想在所有的代碼里用上它。如果像以下的例子中使用的話還是能夠正常運行的:
 

?
1
2
3
4
5
6
7
bar = [42]
def foo():
  bar.append(0)
foo()
 
>>> print bar
[42, 0]

但是,如果我們把bar變一下呢:
 

?
1
2
3
4
5
6
>>> bar = 42
... def foo():
...   bar = 0
... foo()
... print bar
42

我們可以看到foo函數運行的好好的并且沒有拋出異常,但是當我們打印bar的值的時候會發現它的值仍然是42。造成這種情況的原因就是 bar=0 這行代碼,它沒有改變全局變量bar的值,而是創建了一個名字也叫bar的局部變量并且它的值為0。這是個很難發現的bug,這會讓沒有真正理解Python作用域的新手非常痛苦。為了理解Python是如何處理局部變量和全局變量的,我們來看一種更少見的,但是可能會更讓人困惑的錯誤,我們在打印bar的值后定義一個叫bar這個局部變量:
 

?
1
2
3
4
bar = 42
def foo():
  print bar
  bar = 0

這樣寫應該是不會出錯的,不是嗎?我們在打印了值之后定義了相同名稱的變量,所以這應該是不會影響的(Python畢竟是一種解釋型語言),真的是這樣嗎?

 

出錯了

這怎么可能呢?好吧,這里有兩處錯誤。第一點就是關于Python的,作為一種解釋型語言(非常酷,我們都同意這一點),是一行一行地執行的。而事實上,Python是一個聲明一個聲明執行的。為了讓你對我想表達的意思有點感覺,趕緊打開你最愛的shell,然后輸入以下代碼:
 

?
1
def foo():

按回車鍵。正如你看到的,shell里面并沒有打出任何輸出而是等著讓你繼續函數的定義。Shell里會一直這樣直到你停止定義函數。這是因為定義函數是一個聲明。好吧,這是一個混合的聲明,里面包含了一些其他的聲明,但它仍然是一個聲明。直到函數被調用,不然這個函數里的內容是不會執行的。真正執行的是一個function類型的對象被創建出來了。

這引導我們來關注第二點。再強調一下,Python的動態性和解釋型的特性讓我們相信當 print bar 這行被執行的時候,Python會在首先在局部作用域里尋找叫bar的變量然后再去尋找全局作用域里的。但實際上發生的是局部作用域不是完全動態的。當def 這個聲明執行的時候,Python會靜態地從這個函數的局部作用域里獲取信息。當來到 bar=0 這行的時候(不是執行到這行代碼,而是當Python解釋器讀到這行代碼的時候),它會把'bar'這個變量加入到foo函數的局部變量列表里。當foo函數執行并且Python準備執行print bar這行的時候,它就會在局部的作用域里尋找這個變量,由于這個過程是靜態的,Python知道這個變量還沒有被賦值,這個變量沒有值,所以拋出了異常。

你可能會問:為什么不能在聲明函數的時候拋出這個異常呢?Python可以知道預先知道bar這個變量在賦值前被引用了。這個問題的答案就是Python無法知道這個局部變量bar是否被賦值了。看看下面的例子:
 

?
1
2
3
4
5
bar = 42
def foo(baz):
  if baz > 0:
    print bar
  bar = 0

Python在動態和靜態之間玩了一個微妙的游戲。它唯一知道的事情就是bar是被賦值了,但它不知道在賦值前被引用這個異常是否存在直到它真的發生。好吧,老實說,它根本就不知道這個變量是否被賦值!
 

?
1
2
3
4
5
6
7
8
9
10
11
12
13
bar = 42
def foo():
  print bar
  if False:
    bar = 0
 
>>> foo()
Traceback (most recent call last):
 File "<pyshell#17>", line 1, in <module>
  foo()
 File "<pyshell#16>", line 3, in foo
  print bar
UnboundLocalError: local variable 'bar' referenced before assignment

看到上面的代碼里面,雖然我們作為一種智能生物能夠很清楚的知道不會給bar賦值。Python無視了那個事實而是仍然聲明了bar這個局部變量。

關于這個問題我已經說了夠長了。我們需要的是解決方案,我會在這里給出兩個解決方法。
 

?
1
2
3
4
5
6
7
8
9
10
>>> bar = 42
... def foo():
...   global bar
...   print bar
...   bar = 0
...
... foo()
42
>>> bar
0

第一就是使用global關鍵字。這是不言自明的。這會讓Python知道bar是一個全局變量而不是局部變量。

第二個方法,也是更推薦使用的,就是不要使用全局變量。在我的大量Python開發工作中從來沒有用到global這個關鍵字。能知道怎么用它就行了,但最終還是要盡量避免使用它。如果你想保存在代碼里至始至終用到的值的時候,把它定義為一個類的屬性。用這種方法的話就完全不需要用global了,當你要用這個值的時候,通過類的屬性來訪問就可以了:
 

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
>>> class Baz(object):
...   bar = 42
...
... def foo():
...   print Baz.bar # global
...   bar = 0 # local
...   Baz.bar = 8 # global
...   print bar
...
... foo()
... print Baz.bar
42
0
8

 

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 免费一二区 | 亚洲成人第一网站 | 日韩成人在线免费观看 | 精品国产一区二区 | 亚洲一区二区三区在线 | 午夜视频在线观看免费视频 | 日韩一区二区三区在线视频 | 中文字幕精品一区二区三区精品 | 黄色大片在线播放 | 午夜成人免费视频 | 免费在线观看黄视频 | 久久久国产精品入口麻豆 | 成人精品99 | 日本久久影视 | 国产午夜视频 | 国产成人精品免费 | 日韩精品无码一区二区三区 | 午夜精品久久久久久久久久久久 | 欧美日韩亚洲视频 | 97精品久久| 任你躁久久久久久妇女av | 午夜精品久久久久久久99黑人 | 黄色免费在线观看 | 欧美自拍一区 | 最新黄色网址在线播放 | 成年人视频在线观看免费 | 国产黄色小视频 | 日日摸夜夜添夜夜添精品视频 | 国产99精品在线 | 亚洲精品久 | 91久久 | 亚洲国产精品激情在线观看 | 亚洲一区二区在线视频 | 日韩中文字幕在线观看 | 国产精品一区二区视频 | 免费 成 人 黄 色 | 婷婷国产 | 毛片免费在线视频 | 精品女同一区二区三区在线绯色 | 99热在线精品免费 | 日韩欧美中文 |