日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > python >内容正文

python

python legb_Python变量作用域LEGB用法解析

發布時間:2024/2/28 python 30 豆豆
生活随笔 收集整理的這篇文章主要介紹了 python legb_Python变量作用域LEGB用法解析 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

這篇文章主要介紹了Python變量作用域LEGB用法解析,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下

閉包就是, 函數內部嵌套函數. 而 裝飾器只是閉包的特殊場景而已, 特殊在如果外函數的參數是指向一個, 用來被裝飾的函數地址時(不一定是地址哈, 隨意就好) , 就有了 "@xxx" 這樣的寫法, 還是蠻有意思的. 裝飾器的作用是 在不改變原函數的代碼前提下, 額外給原函數填寫新功能. 寫法上來看, 還是比較簡潔優雅的.

裝飾器的通俗寫法

# 裝飾器的通用寫法

def out(func):

def inner(*args, **kwargs):

print("we are checking...", args[0])

return func(*args, **kwargs)

return inner

@out

def check_2019_nCov(name):

return f"now, {name} is very healthy..."

tmp = check_2019_nCov('youge')

print(tmp)

# output

we are checking... youge

now, youge is very healthy...

給裝飾器傳參

雖然這種 "@" 的寫法, 是要求 外函數的參數是一個 func 地址 , 但要達到可以傳參, 只要 再在外面包一層函數 (作用是接受參數) , 這樣不就相當于擴大作用空間, 拿到參數了呀 .

# 最外層的函數作用是, 給裝飾器傳遞參數

def get_param(*args, **kwargs):

def out(func):

def inner(*args, **kwargs):

print("get params", args, kwargs)

return func(*args, **kwargs)

return inner

return out

@get_param("youge")

def check_2019_nCov(name):

return f"now, {name} is very healthy..."

tmp = check_2019_nCov("youge")

print(tmp)

# output

get params ('youge',) {}

now, youge is very healthy...

這種個裝飾器傳遞參數的應用場景, 在 Web應用中, 以 Flask 為例, 就是所有的 路由 url 的概念呀, 如 route("/login") 這樣的寫法, 其原理就是用各種裝飾器來實現 路由 -> 視圖 的映射關系的.

仔細一看, 整個過程忽略了一個重要的話題, 即命名空間, 及 變量的作用域, 或者說命名空間如怎樣的.

LEGB 法則

命名空間

前篇已經詳細闡述過了, Python 變量的本質是指針, 是對象的引用, 而 Python中 萬物皆對象. 這個對象是真正存儲數據的內存地址, 是各種類(數據類型, 數據結構) 的實例. (變量就是用來引用對象的) 差不多這個意思吧.

最為直觀的解釋:

" A namespace is a mapping from names to objects". (變量名和對象的映射)

"Most namespaces are currently implemented as Python dictionaries." (大部分命名空間通過字典來實現)

即命名空間是用來 避免變量命名沖突 的約束. 各個命名空間是彼此獨立的, 一個空間中不能重名, 不同空間中是不沒有關系的. 就跟 計算機系統, 存儲文件是樣的邏輯.

for i in range(10):

print(i)

# 這兩句話都用到了 i 但其各自的空間是不一樣的.

[i for i in range(100)]

內置空間: (built-in names): Python 內置名稱, 如內置函數,異常類...

全局空間: (global names): 常量, 模塊中定義的名稱(類, 導入模塊)...

Enclosed: 可能嵌套在函數內的函數等...

局部名稱: (local names): 函數中定義的名稱(函數內的變量) ...

Python 查找變量順序為:Local -> Enclosed -> Global -> Built-in。

其實, 從我個人經驗而言, 能區分 局部和全局 的 相對性. 就好了, 基本上. 直觀上, 以一個寫代碼的 py文件為例. 最外層有, 變量, 類定義, 函數定義, 從from .. import .. 的變量或函數名, 這些就是 全局變量, 最外面的類或者函數, 里面是各自的名字空間呀.

# var1 是 global

var1 = 666

def foo():

# var2 是局部

var2 = 666

def foo2():

# 內嵌的局部

var3 = 666

# print(var2)

print(var3) # G->L 是找不到的哦

# 在 foo2 中 尋找 var2 是 L->E 是ok的

# 在 foo 中 尋找 var2 是 E->L 是不行的

其實很好理解的. 就上段code來說,根據 L-E-G-B 法則, 其實理解一個 相對 就可以了.

全局 vs 局部

total = 0 # 全局

def sum(a, b):

"""重寫內置sum"""

total = a + b

print("局部total:", total)

sum(1, 1)

print("全局total:", total)

# output

局部total: 2

全局total: 0

可以看到, 局部是不會改變全局的哦, 而在局部內是可以拿到全局變量的. 不然閉包, 外函數接收的參數, 內函數怎么可以拿到呢? 就是外函數, "擴充了" 內函數的作用域呀, 根據 L->E->G->B 法則去搜索到.

global 和 nonlocal

name = "youge"

def change_name():

name = "youyou"

# 希望將 "youge" 改為 "youyou"

change_name()

print(name)

# output

youge

發現沒有能改掉, 這是自然的. 因為, 在調用函數時, 里面的 name 是一個 Local 變量, 是不會影響到全局的 name的, 如果想實現在 在函數內部來改變 全局變量, 則將 該變量用 global 關鍵字聲明即可.

name = "youge"

def change_name():

global name

name = "youyou"

# 希望將 "youge" 改為 "youyou"

change_name()

print(name)

# output

youyou

很簡單, 在函數內部, 用 global 將其聲明為全局變量即可. 同樣, 針對于** 函數嵌套, 即向閉包, 裝飾器等, 通過 關鍵字 nonlocal 實現將 函數內的變量, 聲明為 函數外的 Enclose 層**

name = "jack"

def outer():

name = "youge"

# 函數內有一個local函數空間

def inner():

name = "youyou"

print("local:", name)

inner() # 嘗試改掉 嵌套層的 name

print("encolse:", name)

print("global:", name)

outer()

# output

global: jack

local: youyou

encolse: youge

現在想在, inner函數 (L層) 中來修改 E 層的 name, 即在inner中將 name 聲明為 nonlocal 即可.

name = "jack"

def outer():

name = "youge"

# 函數內有一個local函數空間

def inner():

nonlocal name

name = "youyou"

print("local:", name)

inner() # 嘗試改掉 嵌套層的 name

print("encolse:", name)

print("global:", name)

outer()

# output

global: jack

local: youyou

encolse: youyou

函數嵌套場景中, 通過 在 local 層, 聲明 name 為 nonlocal 則將 enclosed 層的name改掉了. 但如果在 local 層 聲明 global 則是沒有其效果的, 為啥, 嗯... 暫時還不清楚, 也是實驗的, 暫時.

哦, 突然想貼一個, 我還是菜鳥時常, 犯的小錯誤:

name = 'youge'

def change_name():

name = name + "youyou"

change_name()

print(name)

# output

UnboundLocalError: local variable 'name' referenced before assignment

原因就在于, 在函數內部的空間中, 對 name 是沒有定義的. 在 Python中, 對于函數過程的存儲, 是通過 遞歸棧 實現的. 利用棧的 FILO, (先進后出) 的特點, 當遇到一個函數, 就用棧將其參與的成員, 依次入棧, 如有 return 則將置為棧元素.

變量要先定義, 后使用嘛, Python中的定義是指, 該變量指向某個實例對象即可, 而非 其它語言中的 類型聲明 哦, 這里最容易混淆.

修改 name 為全局變量,通過函數參數傳遞即可:

# 方式1: 定義個單獨的函數來處理

name = 'youge'

def change_name(s):

name = s + "youyou"

print(name)

# 全局變量來傳遞給 函數空間, 即"先定義, 后執行")

change_name(name)

# output

yougeyouyou

# 方式2: 聲明為全局即可, 不推薦

name = 'youge'

def change_name():

global name

name = name + "youyou"

change_name()

print(name)

# output

yougeyouyou

小結

閉包, 裝飾器的本質是函數的嵌套, 參數及函數能被傳遞的原因是, Pyhton變量的本質是之指針

Python中用 命名空間 來 解決 變量名沖突, 原理跟 計算機系統(如 Linux) 存儲文件是一樣的邏輯

變量名尋找的規則為 Local -> Enclosed -> Global -> Built-in

個人覺得能理解,全局與局部的"相對性" 即可, 另外, 可用 global 與 nonlocal (E層) 改變變量作用等級.

變量作用域, 一直在用, 但卻經常忽略它, 這里做個總結, 沒事常翻翻, 作用域, 就到這吧.

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持腳本之家。

總結

以上是生活随笔為你收集整理的python legb_Python变量作用域LEGB用法解析的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。