Python_從零開始學習_(31) 變數進階
阿新 • • 發佈:2018-11-02
目錄
1. 變數的引用
- 變數 和 資料 都是儲存在 記憶體 中的
- 在 Python 中 函式的引數傳遞 以及 返回值 都是靠 引用 傳遞
1.1 引用的概念
在 Python 中
- 變數 和 資料 是分開儲存的
- 資料 儲存在記憶體中的一個位置
- 變數 中儲存著資料在記憶體中的地址
- 變數 中 記錄資料的地址, 就叫做 引用
- 使用 id() 函式可以檢視變數中儲存資料所在的 記憶體地址
注意: 如果變數已經被定義, 當給一個變數賦值的時候, 本質上是 修改了資料的引用
- 變數 不再 對之前的資料引用
- 變數 改為 對新賦值的資料引用
1.2 函式的引數和返回值的傳遞
在 Python 中, 函式的 實參 / 返回值 都是靠 引用 來傳遞來的
def test(num): print("在函式內部 %d 對用的記憶體地址是 %d" % (num, id(num))) # 1> 定義一個字串變數 result = "hello" print("%s 的記憶體地址是 %d" % (result, id(result))) # 2> 將字串變數返回, 返回的是資料的引用, 而不是資料本身 return result # 1. 定義一個數字的變數 a = 10 # 資料的地址本質上就是一個數字 print("a 變數儲存資料的記憶體地址是 %d" % id(a)) # 2. 呼叫 test 函式, 本質上傳遞的實參儲存資料的引用, 而不是實參儲存的資料 # 注意: 如果函式有返回值, 但是沒有定義變數接收 # 程式不會報錯, 但是無法獲得返回結構 r = test(a) print("%s 的記憶體地址是 %d" % (r, id(r)))
2. 可變和不可變型別
- 不可變型別, 記憶體中的資料不允許被修改
- 數字型別 int, bool, float, complex, long(2.x)
- 字串 str
- 元組 tuple
- 可變型別, 記憶體中的資料可以被修改 (可以通過append, remove ...等方法修改)
- 列表 list
- 字典 dict
a = [1, 2, 3] print("%s 的記憶體地址是 %d" % (a, id(a))) a.remove(a[0]) print("%s 的記憶體地址是 %d" % (a, id(a))) # 使用方法來改變資料, 記憶體地址不會發生改變 a = [0, 1, 2, 3] print("%s 的記憶體地址是 %d" % (a, id(a))) # 重新定義記憶體地址會發生改變, 因為引用地址變了
注意 : 字典的 key 只能使用不可變型別的資料
d = {"name": "小明", 1: "整數", (1,): "元組"} # 正確的
l = {[1, 2]: "列表"} # 會報錯
- 可變型別的資料變化, 是通過 方法 來實現的
- 如果給一個可變型別的變數, 賦值了一個新的資料, 引用會修改
- 變數 不再 對之前的資料引用
- 變數 改為 對新賦值的資料引用
雜湊 (hash)
- Python 中內建有一個名字叫做 hash(o) 的函式
- 接收一個 不可變型別 的資料作為 引數
- 返回 結果是一個 整數
- 雜湊 是一種 演算法, 其作用就是提取資料的 特徵碼 (指紋)
- 相同的內容 得到 相同的結果
- 不同的內容 得到 不同的結果
- 在 Python 中, 設定字典約 鍵值對 時, 會首先對 key 進行 hash 已決定如何在記憶體中儲存字典的資料, 以方便 後續 對字典的操作: 增, 刪, 改, 查
- 鍵值對的 key 必須是不可變型別資料
- 鍵值對的 value 可以是任意型別的資料
3. 區域性變數
- 區域性變數 是在 函式內部 定義的變數, 只能在函式內部使用
- 全域性變數 是在 函式外部定義 的變數 (沒有定義在某一個函式內), 所有函式 內部 都可以使用這個變數
提示: 在其他的開發語言中, 大多 不推薦使用全域性變數 ---- 可變範圍太大, 導致程式不好維護 !
3.1 區域性變數
- 區域性變數 是在 函式內部 定義的變數, 只能在函式內部使用
- 函式執行結束後, 函式內部的區域性變數, 會被系統回收
- 不同的函式, 可以定義相同的名字的區域性變數, 但是各用個的不會產生影響
區域性變數的作用
- 在函式內部使用, 臨時 儲存 函式內部需要使用的資料
def demo1():
# 定義一個區域性變數
# 1. 執行了下方的程式碼之後, 才會被建立
num = 10
print("在demo1函式內部的變數是 %d" % num)
def demo2():
# 區域性變數同名的變數不會影響
num = 100
print("在demo1函式內部的變數是 %d" % num)
# 在函式內部定義的變數, 不能再其他位置使用
# print("%d" % num)
demo1()
demo2()
區域性變數的生命週期
- 所謂 生命週期 就是變數從 被建立 到 被系統回收 的過程
- 區域性變數 在 函式執行時 才會被建立
- 函式執行結束後 區域性變數 被系統回收
- 區域性變數在生命週期 內, 可以用來儲存 函式內部臨時使用到的資料
4. 全域性變數
- 全域性變數 是在 函式外部定義 的變數, 所以函式內部都可以使用這個變數
# 定義一個全域性變數
num = 10
def demo1():
print("demo1 %d" % num)
def demo2():
print("demo2 %d" % num)
demo1()
demo2()
注意: 函式執行時, 需要處理變數時 會:
1. 首先 查詢 函式內部 是否存在 指定名稱 的區域性變數, 如果有, 直接使用
2. 如果沒有, 查詢 函式外部 是否存在 指定名稱 的全域性變數, 如果有, 直接使用
3. 如果還沒有, 程式報錯!
1) 函式不能直接修改 全域性變數的引用
- 全域性變數 是在 函式外部定義 的變數 (沒有定義在摸一個函式內) , 所有函式 內部 都可以使用這個變數
提示: 在其他的開發語言中, 大多 不推薦使用全域性變數 ---- 可變範圍太大, 導致程式不好維護 !
- 在函式內部, 可以 通過全域性變數的引用獲取對應的資料
- 但是, 不允許直接修改全域性變數的引用 ---- 使用賦值語句修改全域性變數的值
# 定義一個全域性變數
num = 10
def demo1():
# 希望修改全域性變數的值
# 在 Python 中, 是不允許直接修改全域性變數的值
# 如果使用賦值語句, 會在函式內部, 定義一個區域性變數, 變數名相同而已
# num下面的虛線的意思就是, 全域性變數已經有這個名字了,需要自己換一個
num = 100
print("demo1 %d" % num)
def demo2():
print("demo2 %d" % num)
demo1()
demo2()
注意: 只是在函式內部定義了一個區域性變數而已, 只是變數名相同 --- 在函式內部不能直接修改全域性變數的值
2) 在函式內部修改全域性變數的值
- 如果在函式中需要修改全域性變數, 需要使用 global 進行宣告
# 定義一個全域性變數
num = 10
def demo1():
# 希望修改全域性變數的值 - 使用 global 宣告一下變數即可
# global 關鍵字會告訴直譯器後面的變數時一個全域性變數
# 再使用賦值語句時, 就不會建立區域性變數
global num
num = 100
print("demo1 %d" % num)
def demo2():
print("demo2 %d" % num)
demo1()
demo2()
3) 全域性變數定義的位置
- 為了保證所有的函式都能夠正確使用到全域性變數, 應該 將全域性變數定義在其他函式的上方
程式碼結構
shebang => import => 全域性變數 => 函式定義 => 執行程式碼
4) 全域性變數命名的建議
- 為了避免區域性變數和全域性變量出現混淆, 在定義全域性變數時, 有些公司會有一些開發要求, 例如:
- 全域性變數名前應該增加 g_ 或者 gl_ 的字首