變量從作用域分類
作用范圍從小到大為,小作用域的可以調(diào)用大作用域的內(nèi)容。
- 局部 Local
- 閉包 Enclosing
- 全局 Global
- 內(nèi)建 Build-in
局部變量
局部變量是定義在函數(shù)中的,因此其作用域是在函數(shù)內(nèi)部。
def
example
(
)
:
v
=
1
#局部變量
print
(
v
)
由于局部變量作用域只在函數(shù)內(nèi)部有效,因此程序會(huì)報(bào)錯(cuò)
Traceback
(
most recent call last
)
:
File
"test.py"
,
line
3
,
in
<
module
>
print
(
v
)
NameError
:
name
'v'
is
not
defined
全局變量
和局部變量相對,全局變量是定義在函數(shù)外的變量,因此具有更大的作用域。
v
=
1
def
example
(
)
:
print
(
v
)
example
(
)
運(yùn)行結(jié)果
1
注意事項(xiàng)
python與C有許多不同的地方
(1)例子1
v
=
1
def
example
(
)
:
v
=
2
print
(
v
)
example
(
)
print
(
v
)
運(yùn)行結(jié)果
2
1
當(dāng)想要在函數(shù)中對全局變量進(jìn)行賦值時(shí),如上操作,python會(huì)生成新的局部變量,而不是修改全局變量的值,可以通過global標(biāo)記在局部作用域中聲明全局變量。
v
=
1
def
example
(
)
:
global
v
v
=
2
print
(
v
)
example
(
)
print
(
v
)
運(yùn)行結(jié)果
2
2
(1)例子2
def
example
(
)
:
print
(
v
)
v
=
1
example
(
)
運(yùn)行結(jié)果
1
由于python是解釋性語言,不需要進(jìn)行編譯,程序運(yùn)行時(shí)每次讀源文件的一行代碼,并執(zhí)行相應(yīng)的操作,因此上述代碼可以正常運(yùn)行,不會(huì)出現(xiàn)找不到變量v的問題。而當(dāng)我們使用如下代碼則會(huì)報(bào)錯(cuò)。
def
example
(
)
:
print
(
v
)
example
(
)
v
=
1
運(yùn)行結(jié)果
Traceback
(
most recent call last
)
:
File
"test.py"
,
line
4
,
in
<
module
>
example
(
)
File
"test.py"
,
line
2
,
in
example
print
(
v
)
NameError
:
name
'v'
is
not
defined
閉包
在python中“一切皆對象”,因此函數(shù)也被看作對象,因此產(chǎn)生了一種特殊的形式函數(shù)嵌套。如下例子
def
out_func
(
)
:
a
=
1
b
=
2
def
iner_func
(
)
:
return
a
+
1
return
iner_func
閉包是在內(nèi)嵌函數(shù)生成的時(shí)候?qū)⑵溆玫降沫h(huán)境以及自己本身都封裝在了一起。為了直觀理解閉包,我們介紹一下 code 對象, code 對象是指代碼對象,表示編譯成字節(jié)的的可執(zhí)行Python代碼,或者字節(jié)碼。它有幾個(gè)比較重要的屬性:
- co_name: 函數(shù)的名稱
- co_nlocals: 函數(shù)使用的局部變量的個(gè)數(shù)
- co_varnames: 一個(gè)包含局部變量名字的元組
- co_cellvars: 是一個(gè)元組,包含嵌套的函數(shù)所引用的局部變量的名字
- co_freevars: 是一個(gè)元組,保存使用了的外層作用域中的變量名
- co_consts: 是一個(gè)包含字節(jié)碼使用的字面量的元組
有如下程序
def
out_func
(
)
:
a
=
1
b
=
2
c
=
3
def
iner_func1
(
)
:
return
a
+
1
def
iner_func2
(
)
:
return
b
+
1
return
iner_func1
func
=
out_func
(
)
print
(
out_func
.
__code__
.
co_varnames
)
print
(
out_func
.
__code__
.
co_cellvars
)
print
(
out_func
.
__code__
.
co_freevars
)
print
(
func
.
__code__
.
co_varnames
)
print
(
func
.
__code__
.
co_cellvars
)
print
(
func
.
__code__
.
co_freevars
)
運(yùn)行結(jié)果
(
'c'
,
'iner_func1'
,
'iner_func2'
)
(
'a'
,
'b'
)
(
)
(
)
(
)
(
'a'
,
)
前三個(gè)輸出是關(guān)于外部函數(shù)的一些屬性,由于out_func函數(shù)中聲明了幾個(gè)局部變量,因此包含三個(gè)變量。第二個(gè)輸出是內(nèi)部的函數(shù)用到的變量,而iner_func1與iner_func2用到了變量a與b。第三個(gè)輸出是使用了的外部作用域的變量,因此是空。
后三個(gè)輸出是關(guān)于內(nèi)部函數(shù)的一些屬性,前兩個(gè)輸出由于iner_func1沒有使用到因此為空,由于iner_func1用到了外部變量a,因此只有變量a。
若是采用三層的嵌套
def
outout_func
(
)
:
c
=
3
def
out_func
(
)
:
a
=
1
b
=
2
def
iner_func
(
)
:
return
a
+
1
+
c
return
iner_func
return
out_func
(
)
func
=
outout_func
(
)
print
(
func
.
__code__
.
co_varnames
)
print
(
func
.
__code__
.
co_cellvars
)
print
(
func
.
__code__
.
co_freevars
)
運(yùn)行結(jié)果
(
)
(
)
(
'a'
,
'c'
)
在學(xué)習(xí)閉包的過程中,我個(gè)人對一下幾種情況有點(diǎn)蒙圈。
程序一
f
=
[
]
v
=
[
0
]
for
i
in
range
(
5
)
:
v
[
0
]
=
i
def
b
(
)
:
x
=
v
return
x
f
.
append
(
b
)
for
i
in
range
(
5
)
:
print
(
f
[
i
]
(
)
)
print
(
id
(
f
[
i
]
(
)
)
)
運(yùn)行結(jié)果
[
4
]
1618988720712
[
4
]
1618988720712
[
4
]
1618988720712
[
4
]
1618988720712
[
4
]
1618988720712
程序二
f
=
[
]
v
=
[
0
]
for
i
in
range
(
5
)
:
def
b
(
)
:
x
=
v
v
[
0
]
=
i
return
x
f
.
append
(
b
)
for
i
in
range
(
5
)
:
print
(
f
[
i
]
(
)
,
id
(
f
[
i
]
(
)
)
)
運(yùn)行結(jié)果
[
0
]
1397297537608
[
1
]
1397297537608
[
2
]
1397297537608
[
3
]
1397297537608
[
4
]
1397297537608
兩個(gè)程序類似,但是輸出完全不同。
第一個(gè)程序之所以輸出全是相同的,是因?yàn)樵陂]包生成的過程中打包了 v 的地址作為閉包環(huán)境。在函數(shù)調(diào)用時(shí)將 x 指向了相同的地址,也就是 v 的地址,而在函數(shù)調(diào)用之前, v 進(jìn)行了5次賦值,最后一次被賦為了4,因此每次的輸出均相同。
第二個(gè)程序之所以輸出不同,是因?yàn)殚]包在生成過程中將 v 的地址以及 i 的地址都打包了,而 i 指向的是常數(shù),因此具有不同的地址。所以當(dāng)函數(shù)運(yùn)行時(shí), x 先指向了 v 的地址,之后 v 中的數(shù)字被替換為 i 指向的不同常量,因此具有不同的輸出。
在這里若我們將 i 替換為列表會(huì)發(fā)生什么呢,有如下程序
f
=
[
]
ha
=
[
0
]
z
=
[
0
]
for
i
in
range
(
5
)
:
z
[
0
]
=
i
def
b
(
)
:
x
=
ha
ha
[
0
]
=
z
[
0
]
return
x
f
.
append
(
b
)
for
i
in
range
(
5
)
:
print
(
f
[
i
]
(
)
,
id
(
f
[
i
]
(
)
)
)
運(yùn)行結(jié)果
[
4
]
2863541936712
[
4
]
2863541936712
[
4
]
2863541936712
[
4
]
2863541936712
[
4
]
2863541936712
更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號(hào)聯(lián)系: 360901061
您的支持是博主寫作最大的動(dòng)力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點(diǎn)擊下面給點(diǎn)支持吧,站長非常感激您!手機(jī)微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點(diǎn)擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元
