日本免费高清视频-国产福利视频导航-黄色在线播放国产-天天操天天操天天操天天操|www.shdianci.com

學(xué)無先后,達(dá)者為師

網(wǎng)站首頁 編程語言 正文

python 參數(shù)內(nèi)存地址相關(guān)

作者:vincent_duan 更新時間: 2022-09-22 編程語言

查看下某個值的在內(nèi)存中的地址

v1 = 'vincent'
print(id(v1))

v2 = [11,22,33]
v3 = [11,22,33]
print( id(v2) )
print( id(v3) )

我們需要知道的是當(dāng)函數(shù)執(zhí)行傳參時,傳遞的是內(nèi)存地址。驗(yàn)證:

def func(data):
    print(data, id(data)) # vincent 2398921260720

v1 = 'vincent'
func(v1)

print(id(v1)) # 2398921260720 

可以看出傳遞的是內(nèi)存地址。

Python參數(shù)傳遞的特性好處是什么?

  • 主要是可以節(jié)省內(nèi)存。如果執(zhí)行函數(shù)時,每執(zhí)行一次都要創(chuàng)建一個數(shù)據(jù)進(jìn)行傳遞,那么有可能會將同一個數(shù)據(jù)創(chuàng)建很多遍,浪費(fèi)內(nèi)存空間。
  • 當(dāng)傳遞內(nèi)存地址的時候,可以讓函數(shù)幫我們對值的修改。例如:
def func(data):
    data.append(44)

v = [11,22,33]
func(v)
print(v)  # [11, 22, 33, 44]

因?yàn)?code>v和data指向了同一塊內(nèi)存,所以v的值發(fā)生了變化。

不過需要注意的是,要想實(shí)現(xiàn)對值的修改,參數(shù)必須是可變類型(list/dict/set),在函數(shù)內(nèi)部只能對內(nèi)部元素進(jìn)行修改。

例如:

def func(data):
    data.upper() # str是不可變類型,無法進(jìn)行修改

v = 'vincent'
func(v)
print(v) # vincent
def func(data):
    data = [44,55] # 不是對內(nèi)部元素進(jìn)行修改,而是重新賦值

v = [11,22,33]
func(v)
print(v) # [11, 22, 33]

深拷貝

如果想實(shí)現(xiàn)傳值而不是傳地址,那么可以使用深拷貝。

import copy

def func(data):
    data = [44,55]

v = [11,22,33]
new_v = copy.deepcopy(v) # 重新開辟一塊地址空間,不影響v的值
func(new_v)
print(v)

函數(shù)的返回值也是內(nèi)存地址

def func():
    data = [11, 22, 33]
    print(id(data))  # 2875971195072
    return data

v1 = func()
print(v1, id(v1)) # [11,22,33] 2875971195072

上述代碼的執(zhí)行過程:

  • 執(zhí)行func函數(shù)
  • data = [11, 22, 33] 創(chuàng)建一塊內(nèi)存區(qū)域,內(nèi)部存儲[11,22,33],data變量指向這塊內(nèi)存地址。
  • return data 返回data指向的內(nèi)存地址
  • v1接收返回值,所以 v1 和 data 都指向 [11,22,33] 的內(nèi)存地址(兩個變量指向此內(nèi)存,引用計數(shù)器為2)
  • 由函數(shù)執(zhí)行完畢之后,函數(shù)內(nèi)部的變量都會被釋放。(即:刪除data變量,內(nèi)存地址的引用計數(shù)器-1)

所以,最終v1指向的函數(shù)內(nèi)部創(chuàng)建的那塊內(nèi)存地址。

如果兩個函數(shù)進(jìn)行調(diào)用,將返回不一樣的內(nèi)存地址:

def func():
    data = [11, 22, 33]
    print(id(data))
    return data


v1 = func()
print(v1, id(v1))  # [11,22,33] 2187125510336

v2 = func()
print(v2, id(v2))  # [11,22,33] 2187126308352

需要注意的是,如果data是字符串或者整型時,會返回的地址是一樣的,涉及到Python的緩存機(jī)制,這里不表

參數(shù)的默認(rèn)值

當(dāng)我們在函數(shù)中定義了一個參數(shù)默認(rèn)值之后,在函數(shù)定義之后,還未執(zhí)行函數(shù)時,Python解釋器會幫助我們?yōu)楹瘮?shù)創(chuàng)建一塊區(qū)域,存儲參數(shù)的默認(rèn)值。

def func(a1,a2=18):
    print(a1,a2)

原理:Python在創(chuàng)建函數(shù)(未執(zhí)行)時,如果發(fā)現(xiàn)函數(shù)的參數(shù)中有默認(rèn)值,則在函數(shù)內(nèi)部會創(chuàng)建一塊區(qū)域并維護(hù)這個默認(rèn)值。

  • func("root"): 執(zhí)行函數(shù)未傳值時,則讓a2指向 函數(shù)維護(hù)的那個值的地址。
  • func("admin",20):執(zhí)行函數(shù)傳值時,則讓a2指向新傳入的值的地址。

在特定情況【默認(rèn)參數(shù)的值是可變類型 list/dict/set】 & 【函數(shù)內(nèi)部會修改這個值】下,參數(shù)的默認(rèn)值 有坑 。

# 在函數(shù)定義的時候,a2初始化了,后面將不會重新初始化
def func(a1,a2=[1,2]):
    a2.append(666)
    print(a1,a2)

func(100) # 100 [1, 2, 666]
func(200) # 200 [1, 2, 666, 666] 
func(99, [77,88]) # 99 [77, 88, 666] a2重新指向了一個新的內(nèi)存地址,但不影響剛初始化的那塊地址
func(300) # 300 [1, 2, 666, 666, 666] a2繼續(xù)用函數(shù)初始化的那塊地址

原文鏈接:https://blog.csdn.net/vincent_duan/article/details/125553573

欄目分類
最近更新