點選(此處)折疊或打開
- #!/usr/bin/env python
- #-*- coding:utf8 -*-
- #python對變量的操作都是在命名空間中(作用域),變量名被指派的位置決定了這個變量名能被通路到的範圍。
- #變量指派的地方決定了命名空間,即語義作用域。
- #一個函數所有變量名都與函數的命名空間相關。
- '''
- def内定義的變量名隻能在def内使用。
- def内外的變量名不沖突。
- 變量對應的作用域: 作用于可以防止程式變量名沖突。
- def内指派就是def内。
- 嵌套def,對于嵌套函數是非本地。
- def外指派,是全局的。
- X=99#全局變量
- def func():
- X=88 #函數本地變量
- #函數定義了本地作用哉,子產品定義了全局作用域。
- 内嵌的子產品是全局作用域。
- 全局作用域的範圍僅限單個檔案。(全局是相對一個子產品或檔案而言。)
- 每次對函數的調用都建立了一個新的本地作用域。
- 指派的變量名除非聲明為全局變量或本地變量,否則均為本地變量。
- 所有其它的變量名都可以歸納為本地、全局、或都内置的。
- 此外,原處改變對象并不會把變量劃分為本地變量,隻有對變量名指派才可以。即修改一個對象并不是對一個名稱指派。
- print('變量名解析:LEGB原則')
- 變量名按:本地(L)->上層函數(E)->全局(G)->内置(B)的順序查找
- 預設變量名指派會建立或改變本地變量。(指派總是建立或改變變量名,除非聲明過類型。)
- 全局聲明與非本地聲明将指派變量名映射到子產品内部的作用域。
- #全局變量
- X=99 #X與func在本子產品中是:全局變量
- def func(Y): #Y與Z在函數中是本地變量
- #本地變量
- Z=X+Y #X是全局變量
- return Z
- print(func(1))
- #内置作用域 __builtin__ 内置子產品
- #import __builtin__
- #print(dir(__builtin__))
- #global語句
- 全局變量是位于子產品檔案内部頂層的變量
- 全局變量在函數内必須經過聲明
- 全局變量在函數内不用聲明可以引用
- X=88 #全局變量
- global X #全局變量聲明
- X=99
- return X
- print(func())
- print(X)
- a,b=1,2
- def all_global():
- global x
- x=a+b
- print(x)
- all_global()
- print(x)
- #最小化全局變量
- #原因是:流程控制比較難,儲存狀态資訊過于複雜。
- #最小化檔案間的修改
- #隐性的跨檔案依賴性,在最好的情況下會導緻代碼不靈活,最壞的情況會引發bug。
- import t17mod
- t17mod.test()
- #這個例子表明全局變量與子產品的屬性是等效的。但比global要多寫許多語句。
- 作用域和嵌套函數
- #按照LEGB法測,如果嵌套函數将一個變量聲明為全局變量,它将改變整個子產品作用域。如果我們隻想想必被嵌套函數同為此變量名的變量的作用域,可以使用nonlocal聲明,指派會修改最近的嵌套函數中的變量的作用域
- print('作用域和嵌套函數')
- TT=99 #全局作用
- def f1():
- TT=88 #本地作用
- def f2(): #f2是f1函數的本地變量
- print(TT) #根據LEGB法則,X=88
- f2()
- f1()
- #工廠函數,一個能記住嵌套作用域的變量值的函數,雖然有可能那個作用域已經不存在了。但類是最适合做記憶狀态的。
- #本地作用域中N被作為執行的狀态資訊保留下來。
- def maker(N):
- def action(M):
- return N*M
- return action
- f = maker(5) #N=5
- print(f(2)) #M=2,N是被記憶的為5
- #新建立的函數不影響原來的
- g=maker(9)
- print(g(2))
- print(f(2))
- 盡量避免在def中内嵌套def。隻要第二個函數定義在第一個函數調用前就可行。
- 如此可以避免使用嵌套
- x=100
- f2(x)
- def f2(x):
- 嵌套作用域和lambda
- lambda是一個表達式,但類似def,會生成新的作用域,可以使用在def不能使用的地方,如一個清單或是字典中
- def func(N):
- action=(lambda M : N ** M)
- A=func(5)
- print(A(2))
- print(func(5)(3))
- 作用域與帶有循環變量的預設參數相比較
- lambda或def函數在一個函數中定義,嵌套在一個循環中,并引用了上層函數的一個變量,變量在循環中被改變,但lambda或def函數最後值是最後一次循環後的值,不會受其它循環值影響
- def makeAction():
- acts = []
- for i in range(5):
- acts.append(lambda n : i ** n )
- return acts
- actss=makeAction()
- print(actss[2](2))
- #是以必須把嵌套函數的值傳遞給嵌套作用域的變量
- def makeAction2():
- acts.append(lambda n, i=i: i ** n)
- actsss=makeAction2()
- print(actsss[3](2))
- #actsss[i]i最大不能超過range(5)的最大值。
- print(actsss[4](2))
- 作用域可以被任意嵌套,但是隻有内嵌的函數會被搜尋。
- 在python中,平坦優于嵌套。
- nonlocal允許對嵌套函數作用域中的名稱指派,并且把這樣的名稱作用域查找限制在嵌套def.
- def tester(start):
- state=start
- def nester(label):
- #預設不允許修改嵌套的def作用域中的名稱。
- #state +=1 #UnboundLocalError: local variable 'state' referenced before assignment
- #python3.0中使用nonlocal修改,前提是nonlocal的變量在上層函數中已經指派過。
- #nonlocal隻在上層函數的作用域中查找變量,不會去其它作用域查找。
- #nonlocal state
- #nonlocal nostate #SyntaxError: no binding for nonlocal 'nostate' found
- print(label,state)
- #state +=50
- return nester
- F=tester(100)
- F(111) #111 100
- F(112) #112 150
- #如果建立一個新的副本,不會影響原來的state
- G=tester(10)
- G('egg') #egg 10
- G('egg2') #egg2 60
- F('old') #old 200
- states2 = 9
- def tester2(start):
- def nester2(lable):
- global states2
- states2 = 99
- print(lable,states2)
- return nester2
- H=tester2(1000)
- H('new') #new 99
- #nonlocal語句允許在内在保持可變狀态的多個副本,并且解決了在類無法保證的情況下的簡單的狀态保持。
- #下面使用類實作存狀态保持。
- class ctest:
- def __init__(self,A):
- self.state = A
- def funcA(self,label):
- print(label,self.state)
- self.state +=1
- CL=ctest(88)
- CL.funcA('egg') #('egg', 88)
- CL.funcA('egg2') #('egg2', 89)
- print(CL.state) #90
- #使用__call__運算符重載工具擷取一個執行個體上的直接調用
- class ct:
- def __call__(self,label):
- self.state +=11
- CL1=ct(77)
- CL1('python') #('python', 77)
- CL1('ADD11') #('ADD11', 88)
- #下面這個沒搞通,再研究了。
- def Z(start):
- def Y(lable):
- print(lable,Y.state)
- Y.state += 1
- Y.state = start
- return Y
- X=Z(188)
- X('egg')
- 全局、非本地、類、函數屬性都提供了狀态保持選項。
- 全局隻支援共享資料,類要用OOP知識,類和函數屬性都允許嵌套自身之外通路狀态。最好的工具取決于程式的目的。
t17mod.py
點選(此處)折疊或打開
- #!/usr/bin/env python
- #coding:utf8
- var=99 #全局變量=子產品屬性
- def local():
- var = 0 #本地變量,不影響
- def glob1():
- global var #全局變量
- var +=1 #修改全局var=100
- def glob2():
- var =0
- import t17mod #導入子產品,變成子產品屬性
- t17mod.var +=1
- def glob3():
- var = 0
- import sys
- glob = sys.modules['t17mod'] #對子產品屬性生新指派
- glob.var +=1
- def test():
- print(var)
- local();glob1();glob2();glob3() #按照執行順序,第一個函數不影響全局變量
結果
- /usr/bin/python2.7 /home/talen/PycharmProjects/untitled/t17.py
- 變量名解析:LEGB原則
- 100
- 99
- 3
- 102
- 88
- 10
- 18
- 25
- 125
- 16
- 9
- (111, 100)
- (112, 100)
- ('egg', 10)
- ('egg2', 10)
- ('old', 100)
- ('new', 99)
- ('egg', 88)
- ('egg2', 89)
- 90
- ('python', 77)
- ('ADD11', 88)
- Process finished with exit code 0