Python 函數進階-全局空間和局部空間

来源:https://www.cnblogs.com/msr20666/archive/2022/04/05/16101151.html
-Advertisement-
Play Games

java是什麼? java是java面向對象程式設計語言和java平臺的總稱 java的開發平臺 javaSE:標準版 javaEE:企業版 javaME:嵌入式 JRE和JDK JRE:jre是java運行時環境,包含JVM和運行時所需要的核心類庫 JDK:jdk時java程式開發工具包,包含jr ...


全局空間和局部空間

命名空間

命名空間的概念的提出是為了劃分和控制變數是否可見,以及生存周期的長短;命名空間的作用範圍叫做作用域。

劃分一塊區域保存所有數據,以字典的方式存儲(變數與值形成映射關係)。一共三種。

  1. 內建命名空間:
    • 解釋器啟動時創建,直到解釋器運行結束,生存周期最長;
  2. 全局命名空間:
    • 文件運行時創建,直到解釋器運行結束,生存周期較長;
  3. 局部命名空間:
    • 數調用時,裡面的局部變數才創建,調用結束後即釋放,生存周期較短;

創建和銷毀順序

  • 創建順序:
    • python解釋器啟動->創建內建命名空間->創建全局命名空間->創建局部命名空間
  • 銷毀順序:
    • 函數調用結束後->銷毀函數對應的局部命名空間數據->銷毀全局命名空間數據->銷毀內建命名空間數據

全局變數和局部變數

什麼是全局和局部變數

局部變數就是在函數內部定義的變數,局部變數所在的就是局部命名空間,作用域僅僅在函數內部可見,也就是說只能在函數內部使用。

# 在函數中創建的變數就是局部變數
def func():
   var = '局部變數'

# 局部變數不可以在非對應局部環境中使用
print(var)  # error, 該變數不存在

全局變數就是在函數外部定義的或者使用global在函數內部定義的變數,全局變數所在的命名空間就是全局命名空間,作用域橫跨整個文件,就是說在整個文件中的任何一個地方都可以使用全局變數。

# 在全局環境中創建的變數就是全局變數
var = '全局變數'

def func():
	# 在局部中也可以使用全局變數
	print(var)  # 全局變數

func()

局部變數最好不要和全局變數同名,如果同名,在局部環境中就無法使用全局變數了。

var = '全局變數'

def func():
	# 先使用了全局變數
	print(var)  # error, 找不到該變數

	# 然後局部變數和全局變數同名,那麼新的局部變數就會在局部空間中覆蓋了全局變數的一切影響力,這就叫做局部變數修改了全局變數;
	# 這樣的話導致在局部空間中無法在使用該全局變數,之前在局部空間中使用的該變數就成為了先調用後定義;導致出錯。
	var = '局部變數'
	print(var)

func()

# 但是局部同名變數不會影響到全局變數的值
print(var)  # 全局變數


內置函數就是內建命名空間,指的是那些python中自帶的、內置的函數。

作用域

局部變數作用域:在函數的內部

全局變數作用域:橫跨整個文件

生命周期

內置變數 -> 全局變數 -> 局部變數

內置變數自python程式運行的時候開始,一直等到python程式結束之後才會釋放;

全局變數自創建開始,一直到程式結束或者被清除才會釋放;

局部變數字創建開始,一直到局部空間執行結束或者清除就會釋放;

全局部函數和關鍵字的使用

函數

函數 作用
globals() 存放著全局作用域中的所有內容,以字典的形式返回
locals() 存放著當前作用域中的所有內容,以字典的形式返回
globals()

返回所有的全局作用域中的內容。

如果在全局,調用globals之後,獲取的是列印之前的所有變數,返回字典,全局空間作用域;

# 定義一些全局變數
a, b, c = 1, 2, 3

# 調用globals函數
res = globals()

# 第一次列印,包含a b c
print(res)
'''
結果:
{'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x000002DBDCA5D198>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, '__file__': 'E:/0-project/python/mymsr/ceshi/test6.py', '__cached__': None, 'a': 1, 'b': 2, 'c': 3, 'res': {...}}
'''


# 再定義一些變數
d, e, f = 1, 2, 3

# 第二次列印,包含a b c d e f
print(res)
'''
結果:
{'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x000002DBDCA5D198>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, '__file__': 'E:/0-project/python/mymsr/ceshi/test6.py', '__cached__': None, 'a': 1, 'b': 2, 'c': 3, 'res': {...}, 'd': 1, 'e': 2, 'f': 3}
'''

如果在局部,調用globals之後,獲取的是調用之前的所用變數,返回字典,全局空間作用域;

# 定義一些全局變數
a, b, c = 1, 2, 3


# 在局部環境中使用globals函數
def func():
	res = globals()
	print(res)


# 調用函數
func()
'''
結果:不包含 d e f
{'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x000001E7C287D198>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, '__file__': 'E:/0-project/python/mymsr/ceshi/test6.py', '__cached__': None, 'a': 1, 'b': 2, 'c': 3, 'func': <function func at 0x000001E7C2772F28>}
'''


# 再定義一些全局變數
d, e, f = 4, 5, 6

# 第二次調用函數
func()
'''
結果:包含 d e f
{'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x0000021A3F3DD198>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, '__file__': 'E:/0-project/python/mymsr/ceshi/test6.py', '__cached__': None, 'a': 1, 'b': 2, 'c': 3, 'func': <function func at 0x0000021A3F2D2F28>, 'd': 4, 'e': 5, 'f': 6}
'''

globals可以動態創建全局變數

dic = globals()

print(dic)  # 返回系統的字典
'''
結果:
{'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x0000026F357ED198>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, '__file__': 'E:/0-project/python/mymsr/ceshi/test6.py', '__cached__': None, 'dic': {...}}
'''


# 在全局的字典當中,通過添加鍵值對,自動創建全局變數,對應的鍵是變數名,對應的值是變數指向的值
dic['msr123123123'] = '123456'

print(msr123123123)	# 123456

# 查看全局內容
print(dic)
'''
結果:
{'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x00000161D944D198>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, '__file__': 'E:/0-project/python/mymsr/ceshi/test6.py', '__cached__': None, 'dic': {...}, 'msr123123123': '123456'}
'''
locals()

返回當前所在作用域的所有內容。

如果在全局,調用locals之後,獲取的是列印之前的所有變數,返回字典,全局空間作用域;

# 定義一些全局變數
a, b, c = 1, 2, 3

# 調用locals函數
res = locals()

# 第一次列印,包含a b c
print(res)
'''
結果:
{'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x0000018C82A3D198>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, '__file__': 'E:/0-project/python/mymsr/ceshi/test1.py', '__cached__': None, 'a': 1, 'b': 2, 'c': 3, 'res': {...}}
'''


# 再定義一些變數
d, e, f = 1, 2, 3

# 第二次列印,包含a b c d e f
print(res)
'''
結果:
{'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x0000018C82A3D198>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, '__file__': 'E:/0-project/python/mymsr/ceshi/test1.py', '__cached__': None, 'a': 1, 'b': 2, 'c': 3, 'res': {...}, 'd': 1, 'e': 2, 'f': 3}
'''

如果在局部,調用locals之後,獲取的是調用之前的所有變數,返回字典,局部空間作用域;

# 定義一些局部變數
def func():
   # 局部變數
   aa, bb, cc = 11, 22, 33

   # 第一遍調用
   res = locals()

   # 第一次列印,包含 aa bb cc
   print(res)  # {'cc': 33, 'bb': 22, 'aa': 11}

   # 再定義一些局部變數
   dd, ee, ff = 44, 55, 66

   # 第二次列印,不包含 dd ee ff
   print(res)  # {'cc': 33, 'bb': 22, 'aa': 11}

   # 調用第二遍
   res2 = locals()

   # 列印第一次的調用,包含 dd ee ff
   print(res)  # {'cc': 33, 'bb': 22, 'aa': 11, 'ff': 66, 'ee': 55, 'dd': 44, 'res': {...}}
   
   # 列印第二次的調用,包含 dd ee ff
   print(res2) # {'cc': 33, 'bb': 22, 'aa': 11, 'ff': 66, 'ee': 55, 'dd': 44, 'res': {...}}

# 調用函數,返回在函數中的局部變數
func()

關鍵字

關鍵字 作用
global 聲明全局變數、獲取使用和修改全局變數的許可權
nonlocal 修改局部變數(當前函數的上一層的局部變數)
global

在局部環境中創建的變數是局部變數,在全局環境中是不可以使用的。但是使用global定義的變數就是一個全局變數,這個變數可以全局環境中使用。

def func():
	var = '局部變數'

	global glvar
	glvar = '全局變數'

# 一定要執行局部環境喲
func()

# 全局環境中
print(var)  # error,局部變數不能調用
# 使用global定義的變數是全局變數
print(glvar)    # 全局變數

在局部環境中無法修改全局變數的值,使用global可以在局部環境中修改全局變數。

var = '全局變數'

def func():
	global var
	var = '局部環境中修改'

func()

print(var)  # 局部環境中修改

函數的嵌套

在學習nonlocal之前我們需要先學習一些關於函數嵌套的知識。

內函數和外函數

函數之間是可以互相嵌套的,外層的叫做外函數,內層的叫做內函數。

def outer():
	print('我叫outer,是外函數')

	def inner():
		print('我叫inner,在outer的裡面,是內函數')

	# 在外函數中執行內函數
	inner()


# 執行外函數
outer()

'''
結果:
我叫outer,是外函數
我叫inner,在outer的裡面,是內函數
'''
  1. 內函數不可以直接在外函數外執行調用
  2. 調用外函數後,內函數也不可以在函數外部調用
  3. 內函數只可以在外函數的內部調用
  4. 內函數在外函數內部調用時,有先後順序,必須先定義在調用,因為python沒有預讀機制,這個預讀機制適用於python中的所有場景。
# 外層是outer,內層是inner,最裡層是smaller,調用smaller里的所有代碼
def outer():
	print('我叫outer,是最外層函數,是inner和smaller的外函數')

	def inner():
		print('我叫inner,是outer的內函數,是smaller的外函數')

		def smaller():
			print('我叫smaller,是outer和inner的內函數')

		# 先在inner中執行smaller
		smaller()

	# 然後在outer中執行inner
	inner()

# 最後再執行outer才能執行smaller函數
outer()

'''
結果:
我叫outer,是最外層函數,是inner和smaller的外函數
我叫inner,是outer的內函數,是smaller的外函數
我叫smaller,是outer和inner的內函數
'''

我們在多個函數嵌套的時候要註意,不管外函數還是內函數,都是函數,只要是函數中的變數都是局部變數。

內涵可以使用外函數的局部變數,外函數不能直接使用內函數的局部變數。

LEGB原則

LEGB原則就是一個就近找變數原則,依據就近原則,從下往上,從裡向外,依次尋找。

B————Builtin(Python):Python內置模塊的命名空間    (內建作用域)
G————Global(module):函數外部所在的命名空間        (全局作用域)
E————Enclosing Function Locals:外部嵌套函數的作用域(嵌套作用域)
L————Local(Function):當前函數內的作用域           (局部作用域)

在這裡插入圖片描述

nonlocal

現在我們正式學習nonlocal關鍵字,nonlocal的作用是修改當前局部環境中上一層的局部變數。那麼我們根據這個作用便知道了nonlocal的使用環境至少是一個二級的嵌套環境,且外層的局部環境中必須存在一個局部變數。

def outer():
    # 定義變數
	lvar = 'outer var'

	def inner():
        # 內函數使用nonlocal修改上一層的局部變數
		nonlocal lvar
		lvar = 'inner var'

    # 執行inner函數
	inner()
	print(lvar)

outer() # inner var

假如上一層的局部環境中沒有這個變數怎麼辦,那麼就根據LEGB原則向上尋找。

def outer():
	# 定義變數
	lvar = 'outer var'

	def inner():
		
		def smaller():
			
            # smaller中修改變數,但是inner中沒有,就向上尋找修改outer中的變數
			nonlocal lvar
			lvar = 'smaller var'

		# 執行 smaller函數
		smaller()

	# 執行inner函數
	inner()
	print(lvar)

# 執行outer函數
outer()

如果層層尋找,直到最外層的函數中也沒有這個變數,那麼就會報錯,因為nonlocal只會修改局部變數,如果超出範圍,就會報錯。

var = 1  # 變數在最外層的函數之外,也就是全局變數,nonlocal無法修改

def outer():

   def inner():

      def smaller():

         nonlocal var    # error,沒有局部變數
         var = 2
         print(var)

      smaller()

   inner()

outer()

總結

全局變數和局部變數

局部環境中可以調用全局變數,但是不能修改(但是如果全局變數是可變數據則可以修改其中的值)
全局環境中不能調用局部變數 也不能修改

函數

global()

(在函數內部使用,可以對全局變數進行操作)
1、可以在局部環境中定義全局變數
2、可以在局部環境中修改全局變數

nonlocal()

(在內函數中使用,可以在內函數中修改外函數中的局部變數)

關鍵字

locals

1、locals獲取當前作用域當中所有的變數
如果在全局調用locals之後,獲取的是列印之前的所有變數,返回字典,全局作用域
如果在局部調用loclas之後,獲取的是調用之前的所有變數,返回字典,局部作用域

globals

2、globals只獲取全局空間中的所有變數
如果在全局調用globals之後,獲取的是列印之前的所用變數,返回字典,全局作用域
如果在局部調用globals之後,獲取的是調用之前的所用變數,返回字典,全局作用域


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 一、概述 Hadoop是Apache軟體基金會下一個開源分散式計算平臺,以hdfs(Hadoop Distributed File System)、MapReduce(Hadoop2.0加入了YARN,Yarn是資源調度框架,能夠細粒度的管理和調度任務,還能夠支持其他的計算框架,比如spark)為核 ...
  • 之前瞭解過postgresql的Bitmap scan,只是粗略地瞭解到是通過標記數據頁面來實現數據檢索的,執行計劃中的的Bitmap scan一些細節並不十分清楚。這裡藉助一個執行計劃來分析bitmap scan以及index only scan,以及兩者的一些區別。這裡有關於Bitmap sca ...
  • 註意 一定要按照步驟激活 第一步:打開註冊機器,然後點擊patch,找到安裝Navicat15目錄下麵的exe文件 第二步:打開Navicat啟動文件,然後點擊註冊按鈕,然後點擊註冊機器的Generate按鈕,把文本中的內容填寫進去,然後點擊註冊,這時候會顯示註冊失敗,然後點擊手動激活 第三步,在註 ...
  • web前端開發規範 規範概述 一個人走的更快,一群人可以走的更遠,前提是統一的策略,還要不斷地反省和優化。不管有多少人共同參與同一項目,儘可能確保每一行代碼都像是同一個人編寫的 開發目錄規範 開發環境規範 開發編碼規範 一、目錄及文件命名規範 (一)、例靜態專題頁目錄 - src / html 源代 ...
  • 一、首先需要需要引入需要的包 <script src="https://cdn.bootcss.com/xlsx/0.11.5/xlsx.core.min.js"></script> 二、一個上傳文件的file類型的input標簽 <input type="file" onchange="showP ...
  • 註意如果你的mac是M1處理器 那抱歉當前文章可能不支持了,因為當前模擬器不支持。 3步完成mac uniapp 模擬器配置 1.下載網易mumu模擬器 https://mumu.163.com/mac/index.html 2.安裝 設置 下載完成後安裝運行就是這樣的 選擇屏幕旋轉 手機模式 3. ...
  • 工廠方法模式是什麼 工廠方法模式是一種創建型設計模式, 其在父類中提供一個創建對象的方法, 允許子類決定實例化對象的類型。 為什麼用工廠方法模式 在新增一個產品時,不用去修改已有的代碼。工廠方法將創建產品的代碼與實際使用產品的代碼分離,從而能在不影響其他代碼的情況下擴展產品創建部分代碼。例如,如果需 ...
  • 08-Functions, Parameters、 functions、 first class、 function signatures、 parameter、 pass by value、 p... ...
一周排行
    -Advertisement-
    Play Games
  • 示例項目結構 在 Visual Studio 中創建一個 WinForms 應用程式後,項目結構如下所示: MyWinFormsApp/ │ ├───Properties/ │ └───Settings.settings │ ├───bin/ │ ├───Debug/ │ └───Release/ ...
  • [STAThread] 特性用於需要與 COM 組件交互的應用程式,尤其是依賴單線程模型(如 Windows Forms 應用程式)的組件。在 STA 模式下,線程擁有自己的消息迴圈,這對於處理用戶界面和某些 COM 組件是必要的。 [STAThread] static void Main(stri ...
  • 在WinForm中使用全局異常捕獲處理 在WinForm應用程式中,全局異常捕獲是確保程式穩定性的關鍵。通過在Program類的Main方法中設置全局異常處理,可以有效地捕獲並處理未預見的異常,從而避免程式崩潰。 註冊全局異常事件 [STAThread] static void Main() { / ...
  • 前言 給大家推薦一款開源的 Winform 控制項庫,可以幫助我們開發更加美觀、漂亮的 WinForm 界面。 項目介紹 SunnyUI.NET 是一個基於 .NET Framework 4.0+、.NET 6、.NET 7 和 .NET 8 的 WinForm 開源控制項庫,同時也提供了工具類庫、擴展 ...
  • 說明 該文章是屬於OverallAuth2.0系列文章,每周更新一篇該系列文章(從0到1完成系統開發)。 該系統文章,我會儘量說的非常詳細,做到不管新手、老手都能看懂。 說明:OverallAuth2.0 是一個簡單、易懂、功能強大的許可權+可視化流程管理系統。 有興趣的朋友,請關註我吧(*^▽^*) ...
  • 一、下載安裝 1.下載git 必須先下載並安裝git,再TortoiseGit下載安裝 git安裝參考教程:https://blog.csdn.net/mukes/article/details/115693833 2.TortoiseGit下載與安裝 TortoiseGit,Git客戶端,32/6 ...
  • 前言 在項目開發過程中,理解數據結構和演算法如同掌握蓋房子的秘訣。演算法不僅能幫助我們編寫高效、優質的代碼,還能解決項目中遇到的各種難題。 給大家推薦一個支持C#的開源免費、新手友好的數據結構與演算法入門教程:Hello演算法。 項目介紹 《Hello Algo》是一本開源免費、新手友好的數據結構與演算法入門 ...
  • 1.生成單個Proto.bat內容 @rem Copyright 2016, Google Inc. @rem All rights reserved. @rem @rem Redistribution and use in source and binary forms, with or with ...
  • 一:背景 1. 講故事 前段時間有位朋友找到我,說他的窗體程式在客戶這邊出現了卡死,讓我幫忙看下怎麼回事?dump也生成了,既然有dump了那就上 windbg 分析吧。 二:WinDbg 分析 1. 為什麼會卡死 窗體程式的卡死,入口門檻很低,後續往下分析就不一定了,不管怎麼說先用 !clrsta ...
  • 前言 人工智慧時代,人臉識別技術已成為安全驗證、身份識別和用戶交互的關鍵工具。 給大家推薦一款.NET 開源提供了強大的人臉識別 API,工具不僅易於集成,還具備高效處理能力。 本文將介紹一款如何利用這些API,為我們的項目添加智能識別的亮點。 項目介紹 GitHub 上擁有 1.2k 星標的 C# ...