命名空間與範圍

  • 一個名稱可以參考不同的東西 → 取決於在哪裡使用它
  • Python 程式有各種命名空間 → 在一段程式中,某個名稱是獨一無二,但是與其他命名空間的同一個名稱無關
  • 每一個函式都會定義它自己的命名空間
    • 如果在主程式中定義一個變數,稱為 x;且在一個函式中定義另一個叫做 x 的變數 → 它們參考的是不一樣的東西
    • (這面牆是可以翻過去的)必要的話,可以用各種方式來存取其他命名中的名稱
  • 全域變數
    • 程式的主要部分 → 會定義全域的命名空間
    • 全域的命名空間 → 命名空間中的變數都是全域變數
    • 要存取全域變數,不是函式內的區域變數 → 必須明確地使用 global 關鍵字(明白比隱晦好)
  • 區域變數
    • 如果在函式內不使用 global,Python 會使用「區域的命名空間」 → 所以該變數是區域的。會在函式結束時消失
  • Python 提供兩個函式來存取命名空間的內容:
    • locals() → 會回傳「區域命名空間」的字典內容
    • globals() → 會回傳「全域命名空間」的字典內容

全域變數的值

函式裡面取得全域變數的值

>>> 全域變數 = '字串1'
>>> def 函式名稱1():
        print('文字1:', 全域變數)

# 函式裡面取得全域變數的值
>>> print('文字2:', 全域變數)
文字2: 字串1

>>> 函式名稱1()
文字1: 字串1
>>> animal = 'fruitbat'                                # 將「字串 'fruitbat'」指派給「全域變數 animal」(def 以外指派是全域變數)
>>> 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'                                   # change_local() 函式也有一個叫做 animal 的變數,但變數的位置在「函式的區域命名空間裡面」(變數在 def 裡面)
    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))    # Python 函式 id() 來印出每一個物件獨一無二的值

>>> change_local()                                       # 並證明 change_local() 裡面的 animal 變數與主程式的 animal 是不同的
inside change_local: wombat 4332356920

>>> animal
'fruitbat'

>>> id(animal)
4332360368

要存取全域變數,不是函式內的區域變數 → 必須明確地使用 global 關鍵字

>>> 全域變數 = '字串1'
>>> def 函式名稱2():
        global 全域變數                                    # 要存取全域變數,不是函式內的區域變數 → 必須明確地使用 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?

results matching ""

    No results matching ""