程式語言:Python
簡介:(Global vs. Local) and (Call-by-value? or Call-by-reference?)
NG 範例
print(s) 未定義 s 會失敗,如下
OK 範例
global 變數使用前,需先告知,故需多一行 global s
此時 f() 的 s 變成 global,故 print(s) 顯示 "Local",因為 s 在 f() 內被更改
特殊範例 I
若 global 變數使用前,已有同名的變數會產生 warning,但仍然視為 global 變數
故請將告知的程式碼放置在最前面
特殊範例 II
在Python 3中新增了nonlocal,可以指明變數並非區域變數
且依 函式(Local functon)=> 外包涵式(Endosing function)=> 全域(Global)=> 內建(Builtin)的順序來尋找
也就是 python 的 LEGB(Local,Enclosing,Global,Built-in)規則,即是 Lexical scoping
但只適用於 function,若在 class 則會被限於 class 中,如下範例
特殊範例 III
b 的賦值操作不能執行,原因在於 list comprehension 會創建自己的局部命名空間
所以此時的 a 不是跟原本的 a 同空間
Python 的物件分成兩種
Python 賦於變數時如下,想像有個標籤叫 a,然後貼到數字 1 的物件上
a = 1 而每個物件都有 id,可用 id(obj) 取得
簡單來說,取決於標籤貼的物件
數字物件範例
可以發現 id 號碼並不一樣
List 物件範例
可以發現 id 號碼是一樣的,所以 list 被更改
重新給值 List 物件範例
可以發現重新給值 id 號碼不一樣,所以外部 list 不更改為 [1, 2]
簡介:(Global vs. Local) and (Call-by-value? or Call-by-reference?)
Global vs. Local
簡單範例def f(): s = "Local" print(s) # >> Local s = "Global" f() print(s) # >> Global
NG 範例
print(s) 未定義 s 會失敗,如下
def f():
print(s)
# >> UnboundLocalError: local variable 's' referenced before assignment
s = "Local"
print(s)
s = "Global"
f()
print(s)
OK 範例
global 變數使用前,需先告知,故需多一行 global s
此時 f() 的 s 變成 global,故 print(s) 顯示 "Local",因為 s 在 f() 內被更改
def f(): global s print(s) # >> Global s = "Local" print(s) # >> Local s = "Global" f() print(s) # >> Local, modified in f()
特殊範例 I
若 global 變數使用前,已有同名的變數會產生 warning,但仍然視為 global 變數
故請將告知的程式碼放置在最前面
def f(): s = "Local" print(s) # >> Local # >> SyntaxWarning: name 's' is assigned to before global declaration global s print(s) # >> Local s = "Global" f() print(s) # >> Local
特殊範例 II
在Python 3中新增了nonlocal,可以指明變數並非區域變數
且依 函式(Local functon)=> 外包涵式(Endosing function)=> 全域(Global)=> 內建(Builtin)的順序來尋找
也就是 python 的 LEGB(Local,Enclosing,Global,Built-in)規則,即是 Lexical scoping
但只適用於 function,若在 class 則會被限於 class 中,如下範例
class C(object): x = 'class' def __init__(self): print('in C:', self.x) # class def outer_f(self): x = 'outer' def inner_f(): x = 'inner' print('in inner_f:', x) # inner inner_f() print('in outer_f:', x) # outer x = 'global' c = C() c.outer_f() print('in global:', x) # global======================================================================
class C(object): x = 'class' def __init__(self): print('in C:', self.x) # class def outer_f(self): x = 'outer' def inner_f(): # 需放在前面,不然會發生 warning # SyntaxWarning: name 'x' is assigned to before nonlocal declaration nonlocal x x = 'inner' # 此時修改 outer_f 的 x print('in inner_f:', x) # inner inner_f() print('in outer_f:', x) # inner x = 'global' c = C() c.outer_f() print('in global:', x) # global======================================================================
class C(object): x = 'class' def __init__(self): print('in C:', self.x) def outer_f(self): # SyntaxError: no binding for nonlocal 'x' found nonlocal x # 錯誤,找不到 x,但 global 可正常 x = 'outer' def inner_f(): x = 'inner' print('in inner_f:', x) inner_f() print('in outer_f:', x) x = 'global' c = C() c.outer_f() print('in global:', x)
特殊範例 III
b 的賦值操作不能執行,原因在於 list comprehension 會創建自己的局部命名空間
所以此時的 a 不是跟原本的 a 同空間
class C():
a = '123'
b = [a + i for i in a] #NameError: name 'a' is not defined
print(b)
======================================================================
class C():
a = '123'
b = [i for i in a]
print(b) # ['1', '2', '3']
Call-by-value? or Call-by-reference?
答案:都不是
Python 的物件分成兩種
- Immutable Object:不可修改
- numbers
- booleans
- strings
- tuples
- frozensets
- ...
- Mutable Object:可修改
- list
- dict
- ...
Python 賦於變數時如下,想像有個標籤叫 a,然後貼到數字 1 的物件上
a = 1 而每個物件都有 id,可用 id(obj) 取得
簡單來說,取決於標籤貼的物件
- 若是可修改,就像個籃子,只貼到籃子上,而內容物任意可變
- 若是不可修改,則貼到物件本身,變了當然就換個物件
數字物件範例
可以發現 id 號碼並不一樣
def f(a): a += 1 print(id(a)) >> 2004603344 取得標籤 a 貼上物件的 id 號碼 a = 0 print(id(a)) >> 2004603328 f(a) print(a) >> 0
List 物件範例
可以發現 id 號碼是一樣的,所以 list 被更改
def f(a): a.append(1) print(id(a)) >> 27941584 a = [] print(id(a)) >> 27941584 f(a) print(a) >> [1]
重新給值 List 物件範例
可以發現重新給值 id 號碼不一樣,所以外部 list 不更改為 [1, 2]
def f(a): a.append(1) print(id(a)) >> 28334800 a = [1, 2] print(id(a)) >> 28334840 a = [] print(id(a)) >> 28334800 f(a) print(a) >> [1]
留言
張貼留言