變數
April 11, 2022之前介紹各個內建型態時,多半是直接使用實字寫下一個值,實際在撰寫程式時,這麼寫可不行:
print('圓半徑:', 10)
print('圓周長:', 2 * 3.14 * 10)
print('圓面積:', 3.14 * 10 * 10)
半徑 10 同時出現在程式碼中多個位置,圓周率 3.14 也是,如果將來要修改半徑呢?或者是要使用更精確一些的圓周率,像是 3.14159 呢?你得修改多個地方!
建立變數
若能要求 Python 保留某些名稱,可以對照至 10 與 3.14 這些值,每次要運算時,都透過這些名稱取得對應的值,若將名稱對應的值有變化了,既有的程式碼就會取得新的對應值來運算,這樣不是很方便嗎?
radius = 10
PI = 3.14
print('圓半徑:', radius)
print('圓周長:', 2 * PI * radius)
print('圓面積:', PI * radius * radius)
radius
、PI
這些名稱稱為變數(Variable),因為它們的對應值是可以變動的,如你所見,程式碼清楚多了,原來 10 這個值是半徑(radius),3.14 是圓周率(PI),而不是魔術數字(Magic number ),而公式的部份,像是 2 * PI * radius
,比 2 * 3.14 * 10
有意義的多。
依照型態資訊是記錄在變數之上,或者是執行時期的物件之上,程式語言可以區分為靜態定型(statically-typed)、動態定型(dynamically-typed)語言。
Python 屬於動態定型語言,在執行時期,變數本身沒有型態資訊,建立變數時不用宣告型態,只要命名變數並以指定運算「=
」指定對應的值,就建立了一個變數。在建立變數前就嘗試存取某變數,會發生 NameError
,表示變數未定義的錯誤。例如:
>>> x
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'x' is not defined
>>>
在 Python 中,變數始終是個參考(對應)至值的名稱,指定運算只是改變了變數的參考對象。例如:
>>> x = 1.0
>>> y = x
>>> print(id(x), id(y))
1996838054736 1996838054736
>>> y = 2.0
>>> print(id(x), id(y))
1996838054736 1996838054416
>>>
在上面的範例中,x
一開始參考至 1.0 浮點數物件,而後將 x
參考的物件指定給 y
參考,id
函式能用來取得變數參考的物件記憶體位址值,可以看到一開始 x
與 y
都參考同一物件,之後 y
參考至 2.0,x
與 y
就參考了不同的物件。下面這個例子也顯示,變數在 Python 中只是一個參考:
>>> x = 1
>>> id(x)
1996835088688
>>> x = x + 1
>>> id(x)
1996835088720
>>>
一開始 x
參考至 1整數物件,之後 +
運算後,建立了新的整數物件 2,而後指定給 x
,因此 x
參考至新物件。由於變數在 Python 中,只是個參考至物件的名稱,對於可變動物件,才會有以下的操作結果:
>>> x = [1, 2, 3]
>>> y = x
>>> x[0] = 10
>>> y
[10, 2, 3]
>>>
在指定 y = x
時,x
與 y
就參考了同一個物件,將 x[0]
修改為 10,透過 y
就會看到修改的元素。除了使用 id
察看變數參考的物件位址值,以確認兩個變數是否參考同一物件之外,還可以使用 is
或 is not
運算。例如:
>>> list1 = [1, 2, 3]
>>> list2 = [1, 2, 3]
>>> list1 == list2
True
>>> list1 is list2
False
>>>
==
運用在 list
時,可以逐一比較兩個 list
中的元素是否全部相等,因此在上面,list1 == list2
的結果會是 True
,然而,list1
與 list2
參考了不同的物件,因此 list1 is list2
的結果會是 False
。
鴨子定型
變數本身沒有型態,同一個變數可以前後指定不同的資料型態,若想透過變數操作物件的某個方法,只要確認該物件上確實有該方法即可。例如底下 x
前後分別指定了 list
與 tuple
,然而兩個物件上,都有可查詢元素索引位置的 index
方法,因此並不會出現錯誤:
>>> x = [1, 2, 3]
>>> x.index(2)
1
>>> x = (10, 20, 30)
>>> x.index(20)
1
>>>
這是動態定型語言界流行的鴨子定型(Duck typing):「如果它走路像個鴨子,游泳像個鴨子,叫聲像個鴨子,那它就是鴨子。」
從多型(polymorphism)的角度來看,鴨子定型是次型態多型(subtype polymorphism)的一種形式。
Python 是動態定型語言,然而 Python 3.5 開始,納入了型態提示(Type Hints)特性,可以搭配工具程式,實現靜態型態分析,也就是執行程式前檢查型態方面的錯誤,這之後文件會再談到。
如果某個變數不再需要,可以使用 del
來刪除它。例如:
>>> x = 10
>>> x
10
>>> del x
>>> x
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'x' is not defined
>>>
在其他語言中,可以將變數設定為指定值後無法修改,Python 3.8 以後可以透過型態提示的 Final
,結合 mypy
或 IDE 之類的工具來進行靜態時期檢查。