命名空間與範圍
- 一個名稱可以參考不同的東西 → 取決於在哪裡使用它
- Python 程式有各種命名空間 → 在一段程式中,某個名稱是獨一無二,但是與其他命名空間的同一個名稱無關
- 每一個函式都會定義它自己的命名空間
- 如果在主程式中定義一個變數,稱為 x;且在一個函式中定義另一個叫做 x 的變數 → 它們參考的是不一樣的東西
- (這面牆是可以翻過去的)必要的話,可以用各種方式來存取其他命名中的名稱
- 全域變數
- 程式的主要部分 → 會定義全域的命名空間
- 全域的命名空間 → 命名空間中的變數都是全域變數
- 要存取全域變數,不是函式內的區域變數 → 必須明確地使用 global 關鍵字(明白比隱晦好)
- 區域變數
- 如果在函式內不使用 global,Python 會使用「區域的命名空間」 → 所以該變數是區域的。會在函式結束時消失
- Python 提供兩個函式來存取命名空間的內容:
- locals() → 會回傳「區域命名空間」的字典內容
- globals() → 會回傳「全域命名空間」的字典內容
全域變數的值
函式裡面取得全域變數的值
>>> 全域變數 = '字串1'
>>> def 函式名稱1():
print('文字1:', 全域變數)
>>> print('文字2:', 全域變數)
文字2: 字串1
>>> 函式名稱1()
文字1: 字串1
>>> animal = 'fruitbat'
>>> def print_global():
print('inside print_global:', animal)
>>> print('at the top level:', animal)
at the top level: fruitbat
>>> print_global()
inside print_global: fruitbat
在「函式中」取得「全域變數的值」,並且更改它 → 得到一個錯誤
>>> def 函式名稱2():
print('文字3:', 全域變數)
全域變數 = '字串2'
print('文字4:', 全域變數)
>>> 函式名稱2()
錯誤
>>> def change_and_print_global():
print('inside change_and_print_global:', animal)
animal = 'wombat'
print('after the change:', animal)
>>> change_and_print_global()
Traceback (most recent call last):
File "<pyshell#167>", line 1, in <module>
change_and_print_global()
File "<pyshell#166>", line 2, in change_and_print_global
print('inside change_and_print_global:', animal)
UnboundLocalError: local variable 'animal' referenced before assignment
修改全域變數的值,會修改另一個同樣變數名稱,但這個變數是在函式裡面
>>> def 函式名稱3():
區域變數 = '字串2'
print('文字5:', 全域變數, id(變數))
>>> 函式名稱3()
'文字5:', 字串2, id
>>> 全域變數
'字串1'
>>> id(變數)
id
>>> def change_local():
animal = 'wombat'
print('inside change_local:', animal, id(animal))
>>> change_local()
inside change_local: wombat 4332356920
>>> animal
'fruitbat'
>>> id(animal)
4332360368
要存取全域變數,不是函式內的區域變數 → 必須明確地使用 global 關鍵字
>>> 全域變數 = '字串1'
>>> def 函式名稱2():
global 全域變數
全域變數 = '字串2'
print('文字3:', 全域變數)
>>> 全域變數
'字串1'
>>> 函式名稱2()
文字3: 字串2
>>> 全域變數
'字串2'
>>> def change_and_print_global():
global animal
animal = 'wombat'
print('inside change_and_print_global:', animal)
>>> animal
'fruitbat'
>>> change_and_print_global()
inside change_and_print_global: wombat
>>> animal
'wombat'
locals() 會回傳「區域命名空間」的字典內容;globals() 會回傳「全域命名空間」的字典內容
>>> 全域變數 = '字串1'
>>> def 函式名稱3():
區域變數 = '字串2' # local variable 區域變數
print('locals:', locals())
>>> 全域變數
'字串1'
>>> 函式名稱3()
locals: {'區域變數': '字串2'}
>>> print('globals:', globals()) # reformatted a little for presentation
globals: {'全域變數': '字串1',
'__doc__': None,
'函式名稱3': <function change_it at 0x1006c0170>,
'__package__': None,
'__name__': '__main__',
'__loader__': <class '_frozen_importlib_BuiltinInporter'>,
'__builtins__': <module 'builtins'>}
>>> 全域變數
'字串1'
>>> animal = 'fruitbat'
>>> def change_local(): # change_local() 內的「區域命名空間」只有「區域變數 animal」
animal = 'wombat' # local variable 區域變數
print('locals:', locals())
>>> animal
'fruitbat'
>>> change_local()
locals: {'animal': 'wombat'}
# reformatted a little for presentation
>>> print('globals:', globals()) # 「全域命名空間」裡面有另一個「全域變數 animal」與一些其他的東西
globals: {'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <class '_frozen_importlib.BuiltinImporter'>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, 'animal': 'fruitbat', 'change_local': <function change_local at 0x102ba4598>}
在名稱中使用「底線」與「雙底線」
- 在 Python 中,名稱的開頭與結尾使用兩個底線(__)→ 是被保留的的做法,所以「不能在自己的變數中使用」
- 之所以選擇這種命名模式,是因為正常情況下,應用程式的開發人員不會在變數中使用
- 函式的名稱會被存在「系統變數」→ function.name 內
- 函式的文件字串是 → function.doc
>>> def 函式名稱():
``字串字串``
print('文字1:', 函式名稱.__name__)
print('文字2:', 函式名稱.__doc__)
>>> 函式名稱()
文字1: 函式名稱
文字2: 字串
>>> def amazing():
'''This is the amazing function.
Want to see it again?'''
print('This function is named:', amazing.__name__)
print('And its docstring is:', amazing.__doc__)
>>> amazing()
This function is named: amazing # 如同稍早的 globals 輸出訊息,主程式會被指派給特殊的名稱 __main__
And its docstring is: This is the amazing function.
Want to see it again?