Python中的變量、賦值及函數的參數傳遞概要

Python中的變量、賦值及函數的參數傳遞概要

python中的變量、賦值

python中的變量不是盒子。

python中的變量無法用“變量是盒子”做解釋。圖說明了在 Python 中為什么不能使用盒子比喻,而便利貼則指出了變量的正確工作方式。

如果把變量想象為盒子,那么無法解釋 Python 中的賦值;應該把變量視作便利貼,這樣示例中的行為就好解釋了

注意:

對引用式變量來說,說把變量分配給對象更合理,反過來說就有問題。畢竟,對象在賦值之前就創建了。

上面這一段是《流暢的Python》說法。

在 Python 中,一切皆為對象。對象分為不可變對象和可變對象。每個對象都有各自的 id、type 和 value。

Id:當一個對象被創建后,在對象生命周期內它的 id 就不會在改變,在 CPython 實現中,id 通常等于對象的內存地址,可以使用 id() 去查看對象在內存中地址。不可對象(如元組)可能包含可變子對象,子對象的修改不會影響容器的 id。

Type:對象類型(如 int, str, list),決定了支持的操作,通過 type() 獲取。

Value:對象存儲的具體數據。

可變性的本質

??? 可變性取決于對象是否允許 原地修改(即不改變 id 的情況下修改 value)。

??? 不可變對象看似“修改”時,實際上是創建新對象并重新賦值給變量。(不可變對象的“不可變”是指 value 不可原地修改,而非完全不可變。任何對不可變對象的“修改”都會生成新對象。)

# 不可變對象示例(整數)
a = 10
print(id(a))  # 輸出初始 id
a += 5
print(id(a))  # id 改變,因為創建了新對象# 可變對象示例(列表)
b = [1, 2]
print(id(b))  # 輸出初始 id
b.append(3)
print(id(b))  # id 不變,原地修改

學過C/C++可知,python與C/C++不一樣,它的變量使用有自己的特點。下面,就進行必要的展開介紹。

在Python中,變量賦值的機制涉及到對象的引用和對象的可變性。變量名只是對象的引用,而不是直接存儲數據。因此,變量a和b賦值后的行為差異,取決于兩個因素:

在Python中,數據對象被明確劃分為兩大陣營:可變(Mutable)與不可變(Immutable)。

不可變數據類型

??? 數字類型(int/float/complex)

??? 字符串(str)

??? 元組(tuple)

??? 不可變集合/凍結集合(frozenset)

??? 布爾值(bool)

不可變數據類型的核心特性

1.內存機制:當嘗試修改不可變對象時,Python不會改變原對象,而是創建一個新對象。例如:

a = 10
b = a
a += 5  # a指向新對象15,不可變對象的重新賦值,無法原地修改,必須生成新對象
print(id(a), id(b))  # 輸出不同內存地址
print(id(a) == id(b))  # 輸出 False

2. 內存效率優化

對象復用:Python對部分不可變對象(如小整數范圍-5到256、部分短字符串)會進行緩存優化,相同值的對象可能復用同一內存地址。

垃圾回收:不可變對象更易被識別為垃圾,提升回收效率。

3. 哈希性能提升

快速查找:不可變對象的哈希值在創建時確定且不可變,適合作為字典鍵。字典查找時間復雜度O(1)。

安全保障:哈希值穩定性防止字典鍵沖突導致的邏輯錯誤。

4. 線程安全保證

不可變對象天然線程安全,因為無法被修改;可變對象在多線程環境中需使用鎖(如 threading.Lock)來保證數據一致性。

不可變 vs 可變

特性

不可變類型

可變類型

內存占用

低(注:不可變類型的低內存占用僅適用于可復用的對象如小整數,大對象可能仍會獨立存儲)

高(獨立副本)

修改成本

高(需創建新對象)

低(原地修改)

線程安全

否(需加鎖)

哈希支持

適用場景

字典鍵、線程共享數據

頻繁修改的數據集合

☆不可變對象的值一旦創建,就不能修改其內容

1) 修改變量的新賦值

a = 5         # a指向整數對象5
b = a         # b也指向同一個整數對象5
a = 6         # 此時a指向新的整數對象6,但b仍指向5
print(b)      # 輸出5

解釋原因:

賦值操作 b = a 時,僅復制引用,使得 a 和 b 都指向同一個對象(初始是5)。

當 a = 6 時,a 的引用被更新為指向新對象6,而 b 仍然指向原對象

2)不可變對象無法被修改內容,只能重新創建新對象,嘗試直接修改對象內容(無效)

a = "hello"   # a指向字符串"hello"
b = a         # b也指向相同的字符串對象
# 嘗試修改字符串內容(但不可變對象不允許此操作)
a[0] = "H"    # 報錯:'str' object does not support item assignment

☆可變對象的值可以在創建后被修改

1) 直接修改對象內容

a = [1, 2]    # a指向列表[1, 2]
b = a         # b指向同一個列表對象
a.append(3)   # 修改列表內容,原列表變為[1, 2, 3]
print(b)      # 輸出[1, 2, 3]

解釋原因:

a 和 b 指向同一個列表對象。

append() 方法直接修改了該對象的內部內容,因此兩個變量看到的都是同一個被修改后的對象。

可變對象(如列表)在修改時可能觸發動態擴容,導致內存地址變化(如 a = a + [3] 會創建新列表,內存地址改變,而 a.append(3) 是原地修改,內存地址不變)

2) 修改變量的引用(不影響對方)

a = [1, 2]
b = a
a = [3, 4]    # a的引用被更新為新列表[3,4],但b仍指向原列表[1,2]
print(b)      # 輸出[1, 2]

解釋原因:

a = [3,4] 是一個新的賦值操作,直接改變了a的引用,使其指向新對象,而b未被修改,依然指向原列表。

python函數的參數傳遞

python函數的參數傳遞,也有自己的特點。當傳過來的是可變類型(list、dict)時,我們在函數內部修改就會影響函數外部的變量。而傳入的是不可變類型時在函數內部修改改變量并不會影響函數外部的變量,因為修改的時候會先復制一份再修改。

Python的參數傳遞,有人建議表述為:Python的參數傳遞是按對象引用傳遞(pass by object reference),即函數接收的是對象的引用副本,而非對象本身的副本。

官方術語,參數傳遞使用按值調用(call by value)的方式(其中的值始終是對象的引用,而不是對象的值)。實際上,Python函數參數傳遞的始終對象的引用,而不是對象的值。這方面的內容,因一些人和資料介紹的比較混亂,特地附注。

【附注(有關官方文檔節選——同時給出python官方的英文和中文兩種說法節選和鏈接——供參考):

The actual parameters (arguments) to a function call are introduced in the local symbol table of the called function when it is called; thus, arguments are passed using call by value (where the value is always an object reference, not the value of the object). [1] When a function calls another function, or calls itself recursively, a new local symbol table is created for that call.

https://docs.python.org/3/tutorial/controlflow.html#defining-functions

在調用函數時會將實際參數(實參)引入到被調用函數的局部符號表中;因此,實參是使用 按值調用 來傳遞的(其中的 值 始終是對象的 引用 而不是對象的值)。 [1] 當一個函數調用另外一個函數時,會為該調用創建一個新的局部符號表。

https://docs.python.org/zh-cn/3/tutorial/controlflow.html#defining-functions

Remember that arguments are passed by assignment in Python. Since assignment just creates references to objects, there’s no alias between an argument name in the caller and callee, and so no call-by-reference per se.

https://docs.python.org/3/faq/programming.html#how-do-i-write-a-function-with-output-parameters-call-by-reference

請記住,Python 中的實參是通過賦值傳遞的。由于賦值只是創建了對象的引用,所以調用方和被調用方的參數名都不存在別名,本質上也就不存在按引用調用的方式。

https://docs.python.org/zh-cn/3/faq/programming.html#how-do-i-write-a-function-with-output-parameters-call-by-reference 】

這種機制,也有人稱為按對象引用調用(call by object reference),但機制本質不變。

對于不可變對象(如整數、字符串、元組),因為其不可變性,函數內對參數的任何修改不會影響到外部變量。對于可變對象(如列表、字典、集合),函數內對參數的修改會影響到外部變量。

如果傳入的參數是不可變類型(如數字、字符串、元組),那么在函數體內修改參數的值,并不會影響到原來的變量。因為不可變類型的變量實際上是值的引用,當試圖改變變量的值時,相當于是在創建新的對象。例如:

def change_number(num):num = 100x = 10
change_number(x)
print(x)  # 輸出:10

在上面的例子中,盡管在函數內部num的值被改變了,但是原變量x的值并沒有改變。參見下圖:

如果傳入的參數是可變類型(如列表、字典),那么在函數體內修改參數的值,會影響到原來的變量。因為可變類型的變量存儲的是一個地址,當試圖改變變量的值時,實際上是在改變這個地址所指向的內容。例如:

def change_list(lst):lst.append(100)x = [1, 2, 3]
change_list(x)
print(x)  # 輸出:[1, 2, 3, 100]

在上面的例子中,函數內部對參數lst的修改影響到了原變量x的值。參見下圖:

淺拷貝與深拷貝在函數參數傳遞中的作用

函數參數傳遞使用可變對象時,可能涉及淺拷貝問題(如傳入列表時,函數內修改會影響原對象),并建議使用 copy.deepcopy() 避免副作用。

  • 淺拷貝copy.copy()或切片操作(如lst[:]),僅復制頂層對象,嵌套對象仍共享引用。
  • 深拷貝copy.deepcopy(),遞歸復制所有嵌套對象,生成完全獨立的副本。
  • 選擇依據:根據數據結構復雜度和是否需要隔離修改來決定。在涉及嵌套可變對象時,優先使用深拷貝。

通過合理使用copy.deepcopy(),可以確保函數對參數的修改不會意外影響外部數據。

假設有一個函數接收一個列表參數,并在內部修改該列表。由于Python的參數傳遞是對象引用傳遞,直接修改會影響原對象:

def modify_list(lst):lst.append(4)  # 原地修改列表print("函數內列表:", lst)original_list = [1, 2, 3]
modify_list(original_list)
print("函數外列表:", original_list)

輸出:

函數內列表: [1, 2, 3, 4]
函數外列表: [1, 2, 3, 4] ?# 原列表被修改

如果希望避免修改原列表,可以使用淺拷貝(copy.copy()或切片操作),但對于嵌套的可變對象,淺拷貝可能不夠:

import copydef modify_list_shallow(lst):lst_copy = copy.copy(lst)  # 淺拷貝lst_copy.append(4)print("函數內列表:", lst_copy)original_list = [1, 2, 3]
modify_list_shallow(original_list)
print("函數外列表:", original_list)

輸出:

函數內列表: [1, 2, 3, 4]
函數外列表: [1, 2, 3] ?# 原列表未被修改

但當列表包含其他可變對象時,淺拷貝仍可能影響原對象:

def modify_nested_list_shallow(lst):lst_copy = copy.copy(lst)  # 淺拷貝lst_copy[0].append(100)    # 修改嵌套列表print("函數內列表:", lst_copy)original_list = [[1, 2], [3, 4]]
modify_nested_list_shallow(original_list)
print("函數外列表:", original_list)

輸出:

函數內列表: [[1, 2, 100], [3, 4]]
函數外列表: [[1, 2, 100], [3, 4]] ?# 原嵌套列表被修改

使用深拷貝copy.deepcopy()創建完全獨立的副本,即使對象包含嵌套的可變對象:

import copydef modify_list_deep(lst):lst_copy = copy.deepcopy(lst)  # 深拷貝lst_copy[0].append(100)       # 修改嵌套列表print("函數內列表:", lst_copy)original_list = [[1, 2], [3, 4]]
modify_list_deep(original_list)
print("函數外列表:", original_list)

輸出:

函數內列表: [[1, 2, 100], [3, 4]]
函數外列表: [[1, 2], [3, 4]] ?# 原列表未被修改

何時使用深拷貝

  • 需要完全獨立的副本:當函數需要修改傳入的可變對象,但又不希望影響外部變量時。
  • 嵌套可變對象:當對象包含多層嵌套的可變結構(如列表的列表、字典的字典)時,必須使用深拷貝。
  • 避免副作用:在并發編程或需要保持數據隔離的場景中,深拷貝能有效防止意外修改。

OK!?

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/907503.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/907503.shtml
英文地址,請注明出處:http://en.pswp.cn/news/907503.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

KVM 安裝 Ubuntu 22

在 KVM 中安裝 Ubuntu 22 虛擬機。 首先創建硬盤文件 sudo qemu-img create -f qcow2 /app/vms/ubuntu22.qcow2 100G安裝Ubuntu 22 sudo virt-install \--name ubuntu22 \--ram 4096 \--vcpus 2 \--disk path/app/vms/ubuntu22.qcow2,formatqcow2 \--os-type linux \--os-va…

基于生產-消費模式,使用Channel進行文件傳輸(Tcp方式)

Client端: #region 多文件傳輸 public class FileMetadata {public string FileName { get; set; }public long FileSize { get; set; } }class Program {const int PORT 8888;const int BUFFER_SIZE 60 * 1024 * 1024;//15s-50 25s-64 33s-32 27s-50 31s-40 25…

【后端高階面經:Elasticsearch篇】39、Elasticsearch 查詢性能優化:分頁、冷熱分離與 JVM 調優

一、索引設計優化:構建高效查詢的基石 (一)分片與副本的黃金配置 1. 分片數量計算模型 # 分片數計算公式(單分片建議30-50GB) def calculate_shards(total_data_gb, single_shard_gb=30):return max

學習路之PHP--easyswoole3.3安裝入門

學習路之PHP--easyswoole安裝入門 一、安裝swoole擴展二、安裝easyswoole三、指定PHP版本安裝四、啟動swoole五、EasySwoole的入門學習如果報:not controller class match 六、學習推薦: 0、centos 7、php7.2.33、easyswoole 3.3 一、安裝swoole擴展 二、…

Ad Hoc

什么是 Ad Hoc? Ad hoc 一詞源于拉丁語,意為“為此目的”或“為此特定原因”。一般來講,它指的是為解決某一特定問題或任務(而非為了廣泛重復應用)而設計的行動、解決方案或組合。在加密貨幣和區塊鏈領域,…

Lines of Thought in Large Language Models

Lines of Thought in Large Language Models 《Lines of Thought in Large Language Models》(大語言模型中的思維鏈)聚焦于分析大語言模型(LLMs)在生成文本時,其內部向量軌跡的統計特性。 核心目標是揭示LLMs復雜的“思維過程”(即文本生成時的隱藏狀態變化)能否被簡…

npm/yarn/pnpm安裝時Sharp模塊報錯解決方法

在安裝依賴模塊時,npm/yarn/pnpm安裝時Sharp模塊報錯解決方法。 打開源代碼發現:使用的下載地址是github地址,就是因為國內經常無法訪問github造成的。 解決辦法: 把涉及到的下載包設置不要從github上下載,設置成淘寶…

基于CEEMDAN-Transformer-BiLSTM的多特征風速氣候預測的完整實現方案及PyTorch源碼解析

基于CEEMDAN-Transformer-BiLSTM的多特征風速氣候預測的完整實現方案及PyTorch源碼解析 一、模型架構設計 1.1 整體框架 該模型采用三級架構設計(圖1): CEEMDAN分解層:對非平穩風速序列進行自適應分解多模態特征融合模塊&#…

ubuntu24.04啟用fcitx 5

在ubuntu24.04中啟用fcitx 5 ubuntu24.04系統自帶三種鍵盤輸入法系統: IBusFcitx 5XIM 系統默認使用的是IBus,這個拼音輸入少了一些智能的味道,比較影響輸入體驗。換用Fcitx 5后,加上搜狗細胞詞庫,感覺很絲滑,特記錄…

【HTML/CSS面經】

HTML/CSS面經 HTML1. script標簽中的async和defer的區別2. H5新特性(1 標簽語義化(2 表單功能增強(3 音頻和視頻標簽(4 canvas和svg繪畫(5 地理位置獲取(6 元素拖動API(7 Web Worker&#xff08…

Dolphin文檔解析從理論到實踐——保姆級教程

論文:https://arxiv.org/abs/2505.14059 代碼:github.com/bytedance/Dolphin 2025年5月,字節開源了文檔解析Dolphin,讓文檔解析效率提升83%。本文將深入解析字節跳動最新開源的Dolphin模型,先看理論再實戰體驗。 現實…

Web3怎么本地測試連接以太坊?

ETHEREUM_RPC_URLhttps://sepolia.infura.io/v3/你的_INFURA_API_KEY 如果你沒有 Infura Key,注冊 Infura 或 Alchemy,拿一個免費測試網節點就行: Infura:https://infura.io Alchemy:Alchemy - the web3 developme…

深化生態協同,寧盾身份域管完成與拓波軟件兼容互認證

在信創產業蓬勃發展的浪潮下,行業生態的兼容適配決定了信創產品是否好用。近日,寧盾身份域管與拓波軟件 TurboEX 郵件系統完成兼容互認證。測試結果顯示寧盾身份域管(信創版)與 TurboEX 郵件服務器軟件相互良好兼容,運…

HDFS存儲原理與MapReduce計算模型

HDFS存儲原理 1. 架構設計 主從架構:包含一個NameNode(主節點)和多個DataNode(從節點)。 NameNode:管理元數據(文件目錄結構、文件塊映射、塊位置信息),不存儲實際數據…

Function calling的過程

文章目錄 逐段講清 **LLM Function Calling(函數調用)** 的典型鏈路。1. 角色與概念 | Actors & Concepts2. 全流程時序 | End-to-End Sequence3. 關鍵細節 | Key Implementation Notes4. 最小可用示例(偽代碼) | Minimal Exa…

GlobalExceptionHandler 自定義異常類 + 處理validation的異常

在 Spring Boot 項目中,?自定義異常通常用于處理特定的業務邏輯錯誤,并結合全局異常處理器(ControllerAdvice)統一返回結構化的錯誤信息。 一.全局異常處理器: 1. 自定義異常類? 定義一個繼承自 RuntimeExceptio…

軟件測試過程中如何定位BUG

在軟件測試過程中,定位BUG是確保軟件質量的關鍵環節。有效的BUG定位不僅能幫助開發人員快速修復問題,還能提升整個軟件項目的效率。以下是軟件測試中定位BUG的系統性方法和策略: 一、復現BUG 步驟: 收集信息:記錄BUG…

如何優化Elasticsearch的搜索性能?

優化 Elasticsearch 的搜索性能需要從索引設計、查詢優化、硬件配置和集群調優等多方面入手。以下是系統化的優化策略和實操建議: 一、索引設計優化 1. 合理設置分片數 分片大小:單個分片建議 10-50GB(超過50GB會影響查詢性能)。分片數量: 總分片數 ≤ 節點數 1000(避免…

臺式電腦CPU天梯圖_2025年臺式電腦CPU天梯圖

CPU的選擇絕對是重中之重,它關乎了一臺電腦性能好壞。相信不少用戶,在挑選CPU的時候不知道誰強誰弱,尤其是intel和AMD兩款CPU之間。下面通過2025年臺式電腦CPU天梯圖來了解下這兩款cpu. 2025年臺式電腦CPU天梯圖 2025年臺式電腦CPU天梯圖包含了老舊型號以及12代、13代、14代…

HarmonyOS_ArkTs_API(1)

HarmonyOS_ArkTs_API(1) 概述 此API服務模塊是獨自開發的應用程序的核心骨架,提供了鴻蒙OS ArkTS客戶端組件和Java Spring Boot后端之間的強大通信接口。該模塊采用清晰的架構方法處理所有HTTP請求、響應解析和錯誤處理,確保系統各部分間通信的一致性和…