iT邦幫忙

2018 iT 邦幫忙鐵人賽
DAY 2
1
Data Technology

30天python雜談系列 第 2

動態型別雜談之二 ——— 所有的變數都是reference

  • 分享至 

  • xImage
  •  

python 動態型別雜談之二

囉唆一下: 以下提到的名詞:常數對象、常數、常量都是一樣的東西,是和變數相對的,變數的值可能會變,但常量不會變,比如說1就是1,1.6就是1.6,'a'就是'a',像這些就是常量

從上一篇我們知道,python在使用一個變數時不需要宣告這個變數的型別,而且在重新賦值的時候,可以存取和原型別不同的常量,那python內部有何實作機制可以讓他有這樣的動態型別特性呢?

答案就是python的所有變數都是一個參考(reference),當我執行a=1這個指令時,事實上不是讓a存取1這個常數對象,而是直接引用1所在的一個記憶體位址,以下為一個範例讓我們實際驗證這個概念:

In python3 shell:
>>> a = 1
>>> b = 1
>>> id(a) # id(a)這個函數會回傳a所在的記憶體位址,但因為每次python都會任意設定記憶體位址,所以各位讀者測試後所得到的值會與範例不太一樣,但重要的是後面結果
34607448
>>> id(b)
34607448
>>> id(1)
34607448  # a,b,1所在的記憶體位址一樣!

從這個概念也可以知道python為何能夠處理動態型別機制,當我為一個變數存入一個新常量,我只要將變數引用這個新常量所在的記憶體位址,不需要耗費工夫考慮"新常數的size多大?","我需要allocate多大的記憶體給變數?"這種C++才會遇到的問題。

但這似乎非常奇怪,所以這些常數對象是一開始就會存在記憶體裡嗎?那世界上無窮多個不同形式的常量(整數常量:1,2,3... ,浮點數常量:'1.3','2.3,... ,字串常量:'a','b','ab',...)都各自存在一個記憶體位置,那記憶體不就永遠不夠了嗎?

並不全是這樣,當然有些是在python最一開始初始化時就被創造出來並存在某位址裡,只要python繼續運作,這些常數對象就永遠不會消失,而有些是執行時需要這個常數對象的時候才會被建構出來,對於a=1這個指令,因為1這個常數對象在python初始化時就被建構出來,所以可以直接引用,但若遇到了a=100000這個指令,python首先會做的,是先建構100000這個對象並讓變數a去引用他。

再來我們要介紹一個新的觀念:mutable object(可變物件)和immutable object(不可變物件),事實上我們剛剛所說的常量(整數常量:1,2,3... ,浮點數常量:'1.3','2.3,... ,字串常量:'a','b','ab',...),在python裡面都視為物件(object),在介紹新的觀念之前,先來一個範例會讓大家比較好了解:

In python3 shell:
>>> a=1  # a == 1
>>> id(a)
10055552
>>> a+=1 # a == 2
>>> id(a)
10055616  # 當a這個變數的內容被程式所改變,並不會影響原本的1這個物件,而是讓a的指針指向位置不同的物件2,所以a所在的記憶體位址會被改變
>>> b=['1'] # b == ['1']
>>> id(b)
140343295524296
>>> b.append('2')  # b == ['1','2']
>>> id(b)
140343295524296  # 當b這個變數的內容被程式所改變,b不會改變引用的記憶體位址,而是改變原本的物件['1'],使之變為['1','2']

上面範例讓a指向一個整數物件,此為一個immutable object,因此無論程式如何操作變數a的值,都不會更改原本的整數物件,而是讓a重新指向不同位址的物件(但若後者的物件不存在的話python會先建構他再讓a重新指向),而b所指向的是一個list物件,此為mutable object,因此操作b這個變數相當於直接操作這個list物件,而讓物件內容被改變,另外python的dict物件也是屬於這種類型的物件。


上一篇
動態型別雜談之一 ——— 前言與動態型別解釋
下一篇
collections雜談之一 ——— dict的key值存不存在乾我屁事
系列文
30天python雜談30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言