變量作用域


Date: 2019-05-27

Author: Sun

變量由作用范圍來限制,按照作用域分類可分為:

  • 全局(global): 在函數外部定義
  • 局部(local):在函數內部定義

1. 命名空間

​ 比如有一個學校,有5個班級,在2班和4班中都有一個叫“小明”的同學,如果在學校的廣播中呼叫“小明”時,2班和4班中的這2個人就納悶了,你是喊誰呢!!!如果是“2班的小王”的話,那么就很明確了,那么此時的2班就是小王所在的范圍,即命名空間

Python中有三種命名空間

a) 局部,函數內的命名空間就是局部的;

b) 全局,模塊內的命名空間就是全局的;

c) 內置,包括異常類型、內建函數和特殊方法,可以代碼中任意地方調用;

命名空間特點

​ Python會把命名后的變量和函數分配到不同的命名空間,並通過名稱來識別它們。

​ Python命名空間是名稱到對象的映射,這就像是字典,鍵名是變量名,值是變量的值。

在Python程序執行過程中,會有局部命名空間、全局命名空間和內建命名空間同時存在。

​ 局部命名空間記錄函數內部的變量、傳入函數的參數、嵌套函數等被命名的對象;

​ 全局命名空間記錄模塊的變量、函數、類及其它導入的模塊等被命名的對象;

locals() 和globals()

在python中,變量是以字典形式存儲的存儲的

globals()是全局變量; locals()則是局部變量

# -*- coding: utf-8 -*-
__author__ = 'sun'
__date__ = '2019/5/27 18:35'

k = 100

def print_1():
    i = 1
    j = 2
    print('locals():', locals())
    print('globals():', globals())

print_1()

輸出:

locals(): {'j': 2, 'i': 1}
globals(): {'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x0000028171B0EFD0>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, '__file__': 'F:/Tx_Project/basic_project/day02/demo/test3.py', '__cached__': None, '__author__': 'sunnychou', '__date__': '2019/5/18 18:35', 'k': 100, 'print_1': <function print_1 at 0x0000028171A12EA0>}

案例

​ 內建命名空間記錄Python自身提供的函數、模塊等被命名的對象。

>>> x = 3
>>> globals()
{'__builtins__': <module '__builtin__' (built-in)>, '__name__': '__main__', '__doc__': None, 'x': 3, '__package__': None}

​ 可以看到變量x,3以字典的形式存放在globals空間內。以之對應的名字空間還有:locals()。

>>> locals()
{'__builtins__': <module '__builtin__' (built-in)>, '__name__': '__main__', '__doc__': None, 'x': 3, '__package__': None}

實際上,你可以通過向名字添加鍵名和值:

>>> globals()['y'] = 5
>>> y
5

全局變量與局部變量

全局變量是在整個py文件中聲明,全局范圍內都可以訪問

局部變量是在某個函數中聲明的,只能在該函數中調用它,如果試圖在超出范圍的地方調用, 就會出問題

全局變量與局部變量兩者的本質區別就是在於作用域

2.變量作用域

作用域是針對變量而言,指申明的變量在程序里的可應用范圍。或者稱為變量的可見性。

按照作用域划分,可以分為:

  • L:Local,局部作用域

  • E:Enclosing,閉包作用域【閉包外的函數中定義的變量】

  • G:Global,全局作用域 在所有函數外定義的變量

  • B:Built-in,內建作用域【內置作用域】

說明

​ 一般在函數體外定義的變量成為全局變量,在函數內部定義的變量稱為局部變量

​ 全局變量所有作用域都可讀,局部變量只能在本函數可讀

​ 函數在讀取變量時,優先讀取函數本身自有的局部變量,再去讀全局變量

​ 全局變量在局部可以使用(即函數內部可以方位函數外部定義的變量)

案例分析

#1 局部作用域  
#局部變量只能在函數內部使用,外部無法引用
#局部變量的作用域從定義開始到函數體結束
def demo():
    num = 20  #局部變量  
    print(num)
demo()
#print(num) 錯誤

#函數作用域
def outter():
   x = 10   #函數作用域,從定義開始到本函數結束
   def inner():
      y = x  #在閉包中可以引用
      print(y)
   return inner
pf = outter()
pf()  #執行閉包
print(pf.__closure__)

#全局作用域
x = 100    #全局作用域  從定義開始到本文件結束
def demo():
   print(x)
print(x)

#內建作用域,是指系統內建的函數或常量,在系統載入時加載,在所有模塊中都可以直接引用
#比如說系統函數
print(max(1,2,3))  #max函數就是內建作用域  哪里都可以引用
def  demo():
    x = 30
    y = 50
    print(max(x, y))

變量作用域查找規則

以 L --> E --> G -->B 的規則查找,即:在局部找不到,便會去局部外的局部找(例如閉包),再找不到就會去全局找,最后到內建作用域中找。

python作用域種類

問題:想想此時運行下面的程序會有輸出嗎?執行會成功嗎?

# -*- coding: utf-8 -*-
__author__ = 'sun'
__date__ = '2019/5/27 13:52'

for i in range(5):
    name = "andy"

print(name)
for i in range(10):
    age = i

print(age)

輸出:

andy
9

​ 代碼執行成功,沒有問題;在Java/C#中,執行上面的代碼會提示name,age沒有定義,而在Python中可以執行成功,這是因為在Python中是沒有塊級作用域的,代碼塊里的變量,外部可以調用,所以可運行成功

(2)局部作用域

​ Python中沒有塊級作用域,但是有局部作用域

# -*- coding: utf-8 -*-
__author__ = 'sun'
__date__ = '2019/5/27 13:52'

# 局部作用域
def func():
    name = "sunny"

print(name)

​ name變量只在func()函數內部中生效,所以在全局中是沒法調用的

問題:

​ 如果在print(name)前調用func()函數呢?對結果是否有影響?

(3)閉包作用域

​ 閉包的作用域,是一個或多個命名空間按照一定規則疊加影響代碼區域;運行時動態的作用域,是按照特定層次組合起來的命名空間。

# -*- coding: utf-8 -*-
__author__ = 'sun'
__date__ = '2019/5/27 13:52'
i = 100

def g():
    print(i)

def f():
    i = 200
    g()

f()

上述運行結果是100

(4)全局作用域

先執行如下程序,觀察結果

# -*- coding: utf-8 -*-
__author__ = 'sun'
__date__ = '2019/5/27 13:52'

number = 100

def process():
    i = 5                 #局部變量,局部作用域
    number += 1
    print(f"i is {i}, number is {number}")

process()

此時會出現UnboundLocalError: local variable 'number' referenced before assignment錯誤。

問題:如何讓一個函數內能訪問一個全局變量呢?

# -*- coding: utf-8 -*-
__author__ = 'sun'
__date__ = '2019/5/27 13:52'

number = 100

def process():
    i = 5                 #局部變量,局部作用域
    global number
    number += 1
    print(f"i is {i}, number is {number}")


process()

通過以上例子,可以知道,通過global關鍵字。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM