8. python函數傳遞值還是引用

這個blog是用來記錄python函數到底傳遞的是引用還是值

  • is 和 == 的區別
  • tuple到底是不是不可變的…
  • 變量的本質
  • 函數傳遞是引用傳遞

1. is 和 ==的區別

==是表示值相同,但是不一定是同一塊內存。而is是表示同一塊內存地址,則值肯定相同。

  • 先舉個簡單的例子:
a = [1, 2, 3]
b = a
print('Address of a: {}, Address of b: {}'.format(id(a), id(b)))
# Address of a: 140262389525768, Address of b: 140262389525768
# 所以可以看出a和b指向的是一塊內存,則 a is b
print(a is b)  # True
  • 深度探索 == 和 is
    下面舉個例子:
a = 1
b = 1
print("a==b ? {}, a is b ? {}".format(a==b, a is b))
# a==b ? True, a is b ? True

a = 11111
b = 11111
print("a==b ? {}, a is b ? {}".format(a==b, a is b))
# a==b ? True, a is b ? True
# 目前嘗試了[-5, 無窮],都是使用的相同的內存。這是爲了省內存,因爲內存中只需要存在一個變量。
# 同樣的字符串也是,內存中只保留一個變量。

總結: 總結的不夠完善,需要專門去了解python緩存池
1. 實際上,爲什麼有些變量可以共用一塊內存呢,是因爲python有緩衝池。

  • 對於整數,最小的整數爲-5可以共用內存,-6就需要每次都要申請內存。目前測試的到的最大整數爲5x10^90
  • 對於string,可以共用一塊內存,因爲string是不可以改變的。

2. tuple到底能不能改變?

首先要明白tuple不可改變指的是,tuple中的元素不能進行賦值,舉例:

a = ([1], [2])
a[0] += [2]
print(a)
TypeError: 'tuple' object does not support item assignment
# 在這個例子中,+=表示兩個過程,先加再賦值,
# 雖然a已經改變爲([1, 2], [2]),但是還會報不能assign的錯誤(即使是同樣的地址)
# 說明加是沒有報錯的。

雖然tuple不能賦值,但是可以append, 或者是in-place的修改

a = ([1], [2])
a[0].append(2)
print(a)   # ([1, 2], [2])  

3. 變量的本質

在python中,變量也是對象的引用,變量存儲的是對象的地址
變量位於棧內存
對象位於堆內存
變量相當於對象的門牌號,或者是引用。變量可以通過這個引用來改變對象的值,也可以通過這個引用訪問對象。

4. 函數傳遞是引用傳遞

結論: 實際上函數的傳遞,不管是可變變量還是不可變變量,傳遞的都是引用

  • 首先第一個結論: 傳遞的都是引用 , 看代碼
    因爲變量和穿進去的變量的地址是一樣的說明是一塊內存,所以是引用,指向的是同一塊內存
def print_variable_id(a):
	print('傳入的變量地址爲: {}'.format(id(a)))
a = [1, 2, 3] # 可變對象
b = -55  # 不可變對象

print('a的地地址爲 {}'.format(id(a)))
print_variable_id(a)

print('b的地址爲{}'.format(id(b)))
print_variable_id(b)
  • 傳遞不可改變的對象是‘值傳遞’,不會改變函數外面的值,實際上是一種假象
def print_variable_id(a):
	a = 2
	print('修改變量後的地址爲: {}'.format(id(a)))
a = 1
print('a的地址爲 {}'.format(id(a)))
print_variable(a)
print('調用函數後,a的地址爲 {}'.format(id(a)))

a的地址爲 10853632
修改變量後的地址爲: 10853664
調用函數後,a的地址爲 10853632

首先要搞明白的是assign在python中是什麼含義,assign表示變量和對象進行綁定,是換了指向,即使是可變變量也是一樣的,如果在函數中進行賦值,函數外的變量也不會改變的。

def print_variable_id(a):
    a = 2  # 賦值會改變變量的地址。
    print('傳入的變量地址爲: {}'.format(id(a)))
a = [1, 2, 3]
print('a的地址爲 {}'.format(id(a)))
print_variable_id(a)
print('調用函數後,a的地址爲 {}'.format(id(a)))

而如果通過引用變量進行修改可變變量則結果就會變化,

def print_variable_id(a):
    a[2] = 10000  # 原地進行修改,不改變變量的地址
    print('傳入的變量地址爲: {}'.format(id(a)))
a = [1, 2, 3]
print('a的地址爲 {}'.format(id(a)))
print_variable_id(a)
print('調用函數後,a的地址爲 {}'.format(id(a)))

a的地址爲 140527304391944
傳入的變量地址爲: 140527304391944
調用函數後,a的地址爲 140527304391944
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章