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關鍵字。