首頁 > 軟體

Python函數中的作用域規則詳解

2022-03-10 16:00:25

Python是靜態作用域語言,但是它自身是一個動態語言。在Python中變數的作用域是由變數在程式碼中的位置決定的,與C語言有些相似,但不是完全一樣。

在Python 2.0及之前的版本中,Python只支援3種作用域,即區域性作用域,全域性作用域,內建作用域;在Python
2.2中,Python正式引入了一種新的作用域 — 巢狀作用域;巢狀作用域的引入,本質上為Python實現了對閉包的支援。

1、簡單介紹一下閉包

def test():
  A = 3
  B = 4
  def stu():
  	C = 3
  	return A+B+C
  return stu
stu = test()
stu

在上述此程式碼中stu方法定義在test的內部,內部函數stu即可以使用外部函數test的變數,我們稱這種行為叫做閉包。

2、在Python中,並不是任何程式碼塊都能引入新的作用域

Python中不是任何程式碼塊都可以引入新的作用域這與C有很大的不同:

在C中:

#include<stdio.h>
int main() {    
if(2 > 0) {        
	int i = 0;
   	 }
    printf("i = %d", i);    
    return 0;
}

在上述程式碼中,if子句引入了一個區域性作用域,變數i就存在於這個區域性作用域中,但對外不可見,因此,接下來在printf函數中對變數i的參照會引發編譯錯誤。

但是,在Python中卻並非如此:

if True:
    i = 0
print i

在上述程式碼中,if子句並沒有引入一個區域性作用域,變數i仍然處在全域性作用域中,因此,變數i對於接下來的print語句是可見的。

實際上,在Python中,只有模組,類以及函數才會引入新的作用域,其它的程式碼塊是不會引入新的作用域的。

在Python中,使用一個變數之前不必預先宣告它,但是在真正使用它之前,它必須已經繫結到某個物件;而名字繫結將在當前作用域中引入新的變數,同時遮蔽外層作用域中的同名變數,不論這個名字繫結發生在當前作用域中的哪個位置。

>>> f()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 2, in f
NameError: name 'i' is not defined
>>>

執行結果報錯

NameError: name ‘i’ is not defined

程式執行時,Python首先在函數f的本地作用域中查詢變數i,查詢失敗,接著在全域性作用域和內建作用域中查詢變數i,仍然失敗,最終丟擲NameError異常。

>>> def f():
...     i = 8
...     print(i)
...
>>> f()
8
>>> print(i)
0
>>>

執行結果顯示

8和0

i = 8是一個名字繫結操作,它在函數f的區域性作用域中引入了新的變數i,遮蔽了全域性變數i,因此f內部的print語句看到的是區域性變數i,f外部的print語句看到的是全域性變數i。

>>> i = 0 
>>> def f():
...     print(i)
...     i = 0
...
>>> f()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 2, in f
UnboundLocalError: local variable 'i' referenced before assignment
>>>

執行結果報錯

UnboundLocalError: local variable ‘i’ referenced before assignment

在上述中,函數f中的變數i是區域性變數,但是在print語句使用它的時候,它還未被繫結到任何物件之上,所以丟擲異常。

3、在Python中,名字繫結在所屬作用域中引入新的變數,同時繫結到一個物件。

名字繫結發生在以下幾種情況之下:

  • 引數宣告:引數宣告在函數的區域性作用域中引入新的變數;
  • 賦值操作:對一個變數進行初次賦值會在當前作用域中引入新的變數,後續賦值操作則會重新系結該變數;
  • 類和函數定義:類和函數定義將類名和函數名作為變數引入當前作用域,類體和函數體將形成另外一個作用域;
  • import語句:import語句在當前作用域中引入新的變數,一般是在全域性作用域;
  • for語句:for語句在當前作用域中引入新的變數(迴圈變數);
  • except語句:except語句在當前作用域中引入新的變數(異常物件);

總結

本篇文章就到這裡了,希望能夠給你帶來幫助,也希望您能夠多多關注it145.com的更多內容!  


IT145.com E-mail:sddin#qq.com