網(wǎng)站首頁 編程語言 正文
查看下某個值的在內(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
- 上一篇:Python 閉包與裝飾器
- 下一篇:Python 短路運(yùn)算符
相關(guān)推薦
- 2022-08-14 C#生成比較短的Token字符串_C#教程
- 2022-10-06 Android?Jetpack庫重要組件WorkManager的使用_Android
- 2022-09-19 Python?matplotlib數(shù)據(jù)可視化圖繪制_python
- 2022-03-26 C語言goto語句簡單使用詳解_C 語言
- 2022-12-27 Golang中int,?int8,?int16,?int32,?int64和uint區(qū)別淺析_Gol
- 2022-04-01 CentOS安裝Docker的方法_docker
- 2022-09-25 python mac版本解釋器安裝
- 2022-03-17 golang實(shí)現(xiàn)數(shù)組分割的示例代碼_Golang
- 最近更新
-
- window11 系統(tǒng)安裝 yarn
- 超詳細(xì)win安裝深度學(xué)習(xí)環(huán)境2025年最新版(
- Linux 中運(yùn)行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎(chǔ)操作-- 運(yùn)算符,流程控制 Flo
- 1. Int 和Integer 的區(qū)別,Jav
- spring @retryable不生效的一種
- Spring Security之認(rèn)證信息的處理
- Spring Security之認(rèn)證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權(quán)
- redisson分布式鎖中waittime的設(shè)
- maven:解決release錯誤:Artif
- restTemplate使用總結(jié)
- Spring Security之安全異常處理
- MybatisPlus優(yōu)雅實(shí)現(xiàn)加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務(wù)發(fā)現(xiàn)-Nac
- Spring Security之基于HttpR
- Redis 底層數(shù)據(jù)結(jié)構(gòu)-簡單動態(tài)字符串(SD
- arthas操作spring被代理目標(biāo)對象命令
- Spring中的單例模式應(yīng)用詳解
- 聊聊消息隊(duì)列,發(fā)送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠(yuǎn)程分支