1. 程式人生 > >Python_從零開始學習_(31) 變數進階

Python_從零開始學習_(31) 變數進階

目錄

 

1.  變數的引用

2.  可變和不可變型別

3.  區域性變數

4.  全域性變數


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]: "列表"}  # 會報錯
  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_ 的字首