Python中全局變量和局部變量的區(qū)別以及使用
0. 前置知識(shí)
0.1 作用域
所謂作用域(Scope),就是變量的有效范圍,就是變量可以在哪個(gè)范圍以內(nèi)使用。
- 有些變量可以在整段代碼的任意位置使用
- 有些變量只能在函數(shù)內(nèi)部使用
- 有些變量只能在 for 循環(huán)內(nèi)部使用
變量的作用域由變量的定義位置決定,在不同位置定義的變量,它的作用域是不一樣的。在Python語(yǔ)言中,變量一般根據(jù)作用域被劃分為兩種:
- 局部變量
- 全局變量。
1. 局部變量
定義:在函數(shù)內(nèi)部定義的變量,它的作用域也僅限于函數(shù)內(nèi)部,出了函數(shù)就不能使用了,我們將這樣的變量稱為局部變量(Local Variable)。
理論:要知道,當(dāng)函數(shù)被執(zhí)行時(shí),Python 會(huì)為其分配一塊臨時(shí)的存儲(chǔ)空間,所有在函數(shù)內(nèi)部定義的變量,都會(huì)存儲(chǔ)在這塊空間中。而在函數(shù)執(zhí)行完畢后,這塊臨時(shí)存儲(chǔ)空間隨即會(huì)被釋放并回收,該空間中存儲(chǔ)的變量自然也就無法再被使用。
例子1:
>>> def demo(): ... text = "在函數(shù)內(nèi)部聲明了一個(gè)變量,這個(gè)變量就是局部變量" ... print(text) ... >>> demo() 在函數(shù)內(nèi)部聲明了一個(gè)變量,這個(gè)變量就是局部變量 >>> print(text) Traceback (most recent call last): File "<stdin>", line 1, in <module> NameError: name 'text' is not defined
在上面的例子中,text變量的聲明(創(chuàng)建)是在函數(shù)demo中,所以它是一個(gè)局部變量,所以在函數(shù)外面是不可以直接使用的。
如果試圖在函數(shù)外部訪問其內(nèi)部定義的變量,Python 解釋器會(huì)報(bào) NameError 錯(cuò)誤,并提示我們沒有定義要訪問的變量,這也證實(shí)了當(dāng)函數(shù)執(zhí)行完畢后,其內(nèi)部定義的變量會(huì)被銷毀并回收。
1.1 問題一:同名變量
我們思考一個(gè)問題,如果在函數(shù)外部和函數(shù)內(nèi)部都定義了同名變量,那么會(huì)怎么樣呢?
>>> def demo(): ... text = "在函數(shù)內(nèi)部聲明了一個(gè)變量,這個(gè)變量就是局部變量" ... print(text) ... >>> text = "在函數(shù)外部創(chuàng)建了同名變量" >>> demo() 在函數(shù)內(nèi)部聲明了一個(gè)變量,這個(gè)變量就是局部變量 >>> print(text) 在函數(shù)外部創(chuàng)建了同名變量
很明顯,因?yàn)樵诤瘮?shù)外部定義了text變量,所以外部在調(diào)用text時(shí)不會(huì)調(diào)用函數(shù)內(nèi)部的text而是調(diào)用前面我們定義的text。
1.2 問題二:函數(shù)調(diào)用函數(shù)外的變量
那函數(shù)可以直接調(diào)用函數(shù)外的變量嗎?
>>> def demo():
... print(f"函數(shù)直接調(diào)用外部變量 [{text}]")
...
>>> text = "在函數(shù)外部創(chuàng)建的變量"
>>> demo()
函數(shù)直接調(diào)用外部變量 [在函數(shù)外部創(chuàng)建的變量]
可以看到,函數(shù)在直接定義時(shí)是可以調(diào)用外部變量的,且不會(huì)報(bào)錯(cuò)。當(dāng)我們調(diào)用函數(shù)時(shí),只要保證其調(diào)用的外部變量存在,則不會(huì)報(bào)錯(cuò),否則就會(huì)報(bào)錯(cuò)。下面是報(bào)錯(cuò)的情況:
>>> def demo():
... print(f"直接調(diào)用main中的變量: {text}")
...
>>> # 此時(shí)main函數(shù)中并沒有text變量
>>> demo()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 2, in demo
NameError: name 'text' is not defined
2. 全局變量
除了在函數(shù)內(nèi)部定義變量,Python 還允許在所有函數(shù)的外部定義變量,這樣的變量稱為全局變量(Global Variable)。
和局部變量不同,全局變量的默認(rèn)作用域是整個(gè)程序,即全局變量既可以在各個(gè)函數(shù)的外部使用,也可以在各函數(shù)內(nèi)部使用。
定義全局變量的方式有以下 2 種:
- 在main函數(shù)中定義的變量
- 在函數(shù)體內(nèi)聲明的全局變量
2.1 第一種聲明方式 —— 在main函數(shù)中定義的變量
其實(shí)我們?cè)趩栴}1.1和問題1.2中已經(jīng)寫了,在函數(shù)體外定義的變量其實(shí)就是全局變量,也就是在main函數(shù)中定義的變量就是全局變量。
舉個(gè)例子:
>>> global_var_1 = "這是一個(gè)全局變量"
>>> global_var_2 = ["這也是一個(gè)全局變量", 123]
>>> # 再定義一個(gè)函數(shù)和局部變量
>>> def demo(local_var_1, local_var_2):
... local_var_3 = "這是一個(gè)局部變量"
... local_var_4 = ("這也是一個(gè)局部變量", 456)
... print(local_var_1)
... print(local_var_2)
... print(local_var_3)
... print(local_var_4)
... print("局部變量打印完畢")
...
>>> demo(1, 2) # 這里傳給函數(shù)的兩個(gè)形參是全局變量
1
2
這是一個(gè)局部變量
('這也是一個(gè)局部變量', 456)
局部變量打印完畢
>>> global_var_1
'這是一個(gè)全局變量'
>>> global_var_2
['這也是一個(gè)全局變量', 123]
2.2 第二種聲明方式 —— 在函數(shù)體內(nèi)聲明的全局變量
在函數(shù)體內(nèi)也是可以創(chuàng)建全局變量的,步驟如下:
def 函數(shù)名稱(形參1, 形參2, ...): # 1. 需在變量前使用關(guān)鍵字`global`進(jìn)行聲明,這樣一個(gè)全局變量就創(chuàng)建好了 gloabl 全局變量名 # 2. 聲明完畢后賦值 全局變量名 = 值 # 3. 在調(diào)用函數(shù)之后,在函數(shù)中聲明的全局變量也就被創(chuàng)建了,否則不會(huì)創(chuàng)建的 函數(shù)名稱(傳參1,傳參2) # 4. 可以任意使用那個(gè)全局變量了 print(全局變量)
2.2.1 正確
>>> def demo():
... # 聲明一個(gè)局部變量var_1
... var_1 = "This is a local variable"
... # 1. 先用global關(guān)鍵詞進(jìn)行全局變量的聲明
... global var_2
... # 2. 再對(duì)全局變量進(jìn)行賦值
... var_2 = "This is a global variable"
... print(f"[在函數(shù)內(nèi)使用] local_var: {var_1}")
... print(f"[在函數(shù)內(nèi)使用] global_var: {var_2}")
...
>>> demo()
[在函數(shù)內(nèi)使用] local_var: This is a local variable
[在函數(shù)內(nèi)使用] global_var: This is a global variable
>>> # 在main函數(shù)中調(diào)用函數(shù)生成的全局變量
>>> print(f"[在main函數(shù)中使用] global_var: {var_2}")
[在main函數(shù)中使用] global_var: This is a global variable
2.2.2 錯(cuò)誤1 —— 沒有調(diào)用函數(shù)就使用函數(shù)內(nèi)部將會(huì)創(chuàng)建的全局變量
如果不調(diào)用函數(shù)就直接使用函數(shù)中創(chuàng)建的全局變量,是會(huì)報(bào)錯(cuò)的,如下:
>>> def demo():
... # 創(chuàng)建一個(gè)局部變量
... var_1 = "局部變量123"
... # 1. 先聲明是全局變量
... global var_2
... # 2. 再進(jìn)行賦值操作
... var_2 = "全局變量456"
...
>>> # 如果不調(diào)用函數(shù)直接使用在函數(shù)中生成的全局變量
>>> print(f"var_2: {var_2}")
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'var_2' is not defined
>>> # 必須先調(diào)用函數(shù)后,函數(shù)中的全局變量才能生成
>>> demo()
>>> print(f"var_2: {var_2}")
var_2: 全局變量456
2.2.3 錯(cuò)誤2 —— 使用global關(guān)鍵字聲明全局變量時(shí)直接對(duì)其進(jìn)行賦值
>>> def demo():
... # 如果聲明時(shí)直接賦值
... global var_1 = "這是一個(gè)全局變量,但是在聲明時(shí)就賦值了"
File "<stdin>", line 3
global var_1 = "這是一個(gè)全局變量,但是在聲明時(shí)就賦值了"
^
SyntaxError: invalid syntax
2.2.4 思考 —— 多個(gè)函數(shù)對(duì)同一變量進(jìn)行全局變量聲明會(huì)報(bào)錯(cuò)嗎?
看例子,很容易:
>>> def func_1():
... global var_1
... var_1 = "abc"
... print(f"[function_1]全局變量var_1已經(jīng)創(chuàng)建: {var_1}")
...
>>> def func_2():
... global var_1
... var_1 = "123"
... print(f"[function_2]全局變量var_1已經(jīng)創(chuàng)建: {var_1}")
...
>>> # 其實(shí)沒什么影響,和賦值的原理是一樣的
>>> # 先調(diào)用func_1
>>> func_1()
[function_1]全局變量var_1已經(jīng)創(chuàng)建: abc
>>> var_1
'abc'
>>> # 再調(diào)用func_2
>>> func_2()
[function_2]全局變量var_1已經(jīng)創(chuàng)建: 123
>>> var_1
'123'
3. 獲取指定作用域范圍中的變量
在一些特定場(chǎng)景中,我們可能需要獲取某個(gè)作用域內(nèi)(全局范圍內(nèi)或者局部范圍內(nèi))所有的變量,Python 提供了以下 3 種方式:
globals()函數(shù)locals()函數(shù)vars(object)函數(shù)
3.1globals()函數(shù)
globals()函數(shù)為 Python 的內(nèi)置函數(shù),它可以返回一個(gè)包含全局范圍內(nèi)所有變量的字典,該字典中的每個(gè)鍵值對(duì),鍵為變量名,值為該變量的值。
>>> globals()
{'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <class '_frozen_importlib.BuiltinImporter'>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, 'demo': <function demo at 0x7ff433a520d0>, 'var_2': '全局變量456', 'func_1': <function func_1 at 0x7ff433a52280>, 'func_2': <function func_2 at 0x7ff433a52160>, 'var_1': '123'}
注意,globals()函數(shù)返回的字典中,會(huì)默認(rèn)包含有很多變量,這些都是 Python 主程序內(nèi)置的,不用理會(huì)它們。
可以看到,通過調(diào)用 globals() 函數(shù),我們可以得到一個(gè)包含所有全局變量的字典。并且,通過該字典,我們還可以訪問指定變量,甚至如果需要,還可以修改它的值。例如,在上面程序的基礎(chǔ)上,添加如下語(yǔ)句:
>>> print(globals()["var_2"])
全局變量456
>>> globals()["var_2"] = "對(duì)這個(gè)全局變量進(jìn)行重新賦值!"
>>> print(globals()["var_2"])
對(duì)這個(gè)全局變量進(jìn)行重新賦值!
>>> globals()
{'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <class '_frozen_importlib.BuiltinImporter'>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, 'demo': <function demo at 0x7ff433a520d0>, 'var_2': '對(duì)這個(gè)全局變量進(jìn)行重新賦值!', 'func_1': <function func_1 at 0x7ff433a52280>, 'func_2': <function func_2 at 0x7ff433a52160>, 'var_1': '123'}
3.2locals()函數(shù)
locals() 函數(shù)也是 Python 內(nèi)置函數(shù)之一,通過調(diào)用該函數(shù),我們可以得到一個(gè)包含當(dāng)前作用域內(nèi)所有變量的字典。這里所謂的“當(dāng)前作用域”指的是:
- 在函數(shù)內(nèi)部調(diào)用
locals()函數(shù),會(huì)獲得包含所有局部變量的字典 - 而在全局范文內(nèi)調(diào)用
locals()函數(shù),其功能和globals()函數(shù)相同。
>>> def demo(a, b):
... c = 10 # 定義局部變量
... global d # 聲明全局變量
... d = 100
... print(locals()) # 查看該函數(shù)的局部變量
... return a + b + c + d
...
>>> # 定義一些全局變量
>>> aaa = 123
>>> bbb = 456
>>> # 查看全局變量
>>> globals()
{'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <class '_frozen_importlib.BuiltinImporter'>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, 'demo': <function demo at 0x7f1132cbd0d0>, 'aaa': 123, 'bbb': 456}
>>> # 查看局部變量
>>> locals()
{'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <class '_frozen_importlib.BuiltinImporter'>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, 'demo': <function demo at 0x7f1132cbd0d0>, 'aaa': 123, 'bbb': 456}
>>> # 調(diào)用函數(shù)
>>> demo(1, 2)
{'a': 1, 'b': 2, 'c': 10}
113
>>> # 查看全局變量
>>> globals()
{'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <class '_frozen_importlib.BuiltinImporter'>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, 'demo': <function demo at 0x7f1132cbd0d0>, 'aaa': 123, 'bbb': 456, 'd': 100}
>>> # 查看局部變量
>>> locals()
{'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <class '_frozen_importlib.BuiltinImporter'>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, 'demo': <function demo at 0x7f1132cbd0d0>, 'aaa': 123, 'bbb': 456, 'd': 100}
Note:
- 當(dāng)使用 locals() 函數(shù)獲得所有局部變量組成的字典時(shí),可以向 globals() 函數(shù)那樣,通過指定鍵訪問對(duì)應(yīng)的變量值,但無法對(duì)變量值做修改。
3.3var(object)函數(shù)
vars() 函數(shù)也是 Python 內(nèi)置函數(shù),其功能是返回一個(gè)指定 object 對(duì)象范圍內(nèi)所有變量組成的字典。如果不傳入object 參數(shù),vars() 和 locals() 的作用完全相同。
>>> class A:
... def __init__(self, a, b, c):
... self.a = a
... self.b = b
... self.c = c
... name = "Leovin"
... school = "xxx University"
...
>>> print(f"vars(A): {vars(A)}")
vars(A): {'__module__': '__main__', '__init__': <function A.__init__ at 0x7fd201d5e160>, 'name': 'Leovin', 'school': 'xxx University', '__dict__': <attribute '__dict__' of 'A' objects>, '__weakref__': <attribute '__weakref__' of 'A' objects>, '__doc__': None}
>>> print(vars())
{'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <class '_frozen_importlib.BuiltinImporter'>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, 'A': <class '__main__.A'>}
>>> print(globals())
{'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <class '_frozen_importlib.BuiltinImporter'>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, 'A': <class '__main__.A'>}
>>> print(locals())
{'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <class '_frozen_importlib.BuiltinImporter'>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, 'A': <class '__main__.A'>}
>>> def func(a, b):
... c = 1
... global d
... d = 10
... return a + b + c + d
...
>>> vars(func)
{}
>>> vars(func(1, 2))
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: vars() argument must have __dict__ attribute
>>> vars()
{'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <class '_frozen_importlib.BuiltinImporter'>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, 'A': <class '__main__.A'>, 'func': <function func at 0x7fd201d5e0d0>, 'd': 10}
>>> vars(A)
mappingproxy({'__module__': '__main__', '__init__': <function A.__init__ at 0x7fd201d5e160>, 'name': 'Leovin', 'school': 'xxx University', '__dict__': <attribute '__dict__' of 'A' objects>, '__weakref__': <attribute '__weakref__' of 'A' objects>, '__doc__': None})
到此這篇關(guān)于Python中全局變量和局部變量的區(qū)別以及使用的文章就介紹到這了,更多相關(guān)Python 全局變量和局部變量?jī)?nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Python使用背景差分器實(shí)現(xiàn)運(yùn)動(dòng)物體檢測(cè)
目前,許多運(yùn)動(dòng)檢測(cè)技術(shù)都是基于簡(jiǎn)單的背景差分概念的,因此本文將基于背景差分器(MOG背景差分器和KNN背景差分器)來實(shí)現(xiàn)運(yùn)動(dòng)物體的檢測(cè),感興趣的可以了解一下2022-02-02
python DES加密與解密及hex輸出和bs64格式輸出的實(shí)現(xiàn)代碼
這篇文章主要介紹了python DES加密與解密及hex輸出和bs64格式輸出的實(shí)現(xiàn)代碼,代碼簡(jiǎn)單易懂,非常不錯(cuò)對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-04-04
Python2.7:使用Pyhook模塊監(jiān)聽鼠標(biāo)鍵盤事件-獲取坐標(biāo)實(shí)例
這篇文章主要介紹了Python2.7:使用Pyhook模塊監(jiān)聽鼠標(biāo)鍵盤事件-獲取坐標(biāo)實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2020-03-03
基于python實(shí)現(xiàn)圖片處理與pdf生成小程序
在日常工作中,我們經(jīng)常需要處理圖片文件并將其整理成PDF文檔,本文將使用Python wxPython開發(fā)一個(gè)圖片處理與pdf生成小程序,感興趣的小伙伴可以了解下2025-09-09
使用Keras構(gòu)造簡(jiǎn)單的CNN網(wǎng)絡(luò)實(shí)例
這篇文章主要介紹了使用Keras構(gòu)造簡(jiǎn)單的CNN網(wǎng)絡(luò)實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2020-06-06
如何使用七牛Python SDK寫一個(gè)同步腳本及使用教程
七牛云存儲(chǔ)的 Python 語(yǔ)言版本 SDK(本文以下稱 Python-SDK)是對(duì)七牛云存儲(chǔ)API協(xié)議的一層封裝,以提供一套對(duì)于 Python 開發(fā)者而言簡(jiǎn)單易用的開發(fā)工具本篇文章給大家介紹如何使用七牛Python SDK寫一個(gè)同步腳本及使用及使用教程,需要的朋友可以參考下2015-08-08
Python使用selenium實(shí)現(xiàn)網(wǎng)頁(yè)用戶名 密碼 驗(yàn)證碼自動(dòng)登錄功能
這篇文章主要介紹了Python使用selenium實(shí)現(xiàn)網(wǎng)頁(yè)用戶名 密碼 驗(yàn)證碼自動(dòng)登錄功能,實(shí)現(xiàn)思路很簡(jiǎn)單,感興趣的朋友跟隨腳本之家小編一起學(xué)習(xí)吧2018-05-05

