最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

python可變/不可變對象及+=和=+舉例詳解

 更新時間:2025年12月01日 10:42:31   作者:JAVA小俠影  
Python中可變數(shù)據(jù)類型指的是數(shù)據(jù)值可以改變的數(shù)據(jù)類型,而不可變數(shù)據(jù)類型指的是數(shù)據(jù)值不可改變的數(shù)據(jù)類型,這篇文章主要介紹了python可變/不可變對象及+=和=+的相關資料,需要的朋友可以參考下

前言

在Python開發(fā)中,“可變對象”與“不可變對象”是一個高頻基礎概念,也是初學者容易混淆的難點。這兩類對象的核心差異不僅影響變量賦值、函數(shù)傳參的邏輯,更直接關系到代碼的性能與安全性。本文將從定義區(qū)分→底層原理→核心差異→實戰(zhàn)場景四個維度,幫你徹底搞懂這兩類對象,避免開發(fā)中因概念模糊導致的BUG。

一、先明確:什么是可變對象?什么是不可變對象?

首先用最通俗的語言定義兩類對象,再通過示例直觀感受差異——核心區(qū)別在于“對象創(chuàng)建后,能否修改其內部數(shù)據(jù)”。

1. 不可變對象(Immutable)

定義:對象創(chuàng)建后,其內部數(shù)據(jù)(值)無法被修改,若要“修改”,只能創(chuàng)建一個新對象并指向新地址。
Python中常見的不可變對象:

  • 基礎類型:int(整數(shù))、str(字符串)、float(浮點數(shù))、bool(布爾值)
  • 容器類型:tuple(元組)、frozenset(凍結集合)
# 示例1:int類型(不可變)
a = 10
print(f"修改前a的值:{a},地址:{id(a)}")  # 輸出:修改前a的值:10,地址:140708484554720

a = a + 2  # 看似“修改”,實際創(chuàng)建新對象
print(f"修改后a的值:{a},地址:{id(a)}")  # 輸出:修改后a的值:12,地址:140708484554784(地址變化)

# 示例2:str類型(不可變)
s = "Python"
print(f"修改前s的值:{s},地址:{id(s)}")  # 輸出:修改前s的值:Python,地址:2524607223408

s = s.replace("P", "p")  # replace()返回新字符串,原對象不變
print(f"修改后s的值:{s},地址:{id(s)}")  # 輸出:修改后s的值:python,地址:2524607223664(地址變化)

# 示例3:tuple類型(不可變)
t = (1, 2, 3)
# t[0] = 100  # 報錯:TypeError: 'tuple' object does not support item assignment(無法修改元素)

2. 可變對象(Mutable)

定義:對象創(chuàng)建后,其內部數(shù)據(jù)(值)可以被直接修改,且修改后對象的地址(身份標識)保持不變。
Python中常見的可變對象:

  • 容器類型:list(列表)、dict(字典)、set(集合)
  • 其他:bytearray(字節(jié)數(shù)組)、自定義類實例(默認可變)
# 示例1:list類型(可變)
lst = [1, 2, 3]
print(f"修改前l(fā)st的值:{lst},地址:{id(lst)}")  # 輸出:修改前l(fā)st的值:[1,2,3],地址:2524607215232

lst.append(4)  # 直接修改列表內部數(shù)據(jù)
print(f"修改后lst的值:{lst},地址:{id(lst)}")  # 輸出:修改后lst的值:[1,2,3,4],地址:2524607215232(地址不變)

# 示例2:dict類型(可變)
d = {"name": "張三", "age": 25}
print(f"修改前d的值:wppm3vysvbp,地址:{id(d)}")  # 輸出:修改前d的值:{'name':'張三','age':25},地址:2524607214848

d["age"] = 26  # 直接修改字典value
print(f"修改后d的值:wppm3vysvbp,地址:{id(d)}")  # 輸出:修改后d的值:{'name':'張三','age':26},地址:2524607214848(地址不變)

# 示例3:set類型(可變)
s = {1, 2, 3}
print(f"修改前s的值:{s},地址:{id(s)}")  # 輸出:修改前s的值:{1,2,3},地址:2524607198976

s.add(4)  # 直接修改集合內部數(shù)據(jù)
print(f"修改后s的值:{s},地址:{id(s)}")  # 輸出:修改后s的值:{1,2,3,4},地址:2524607198976(地址不變)

二、底層原理:為什么會有“可變”與“不可變”之分?

兩類對象的差異本質是內存存儲機制對象身份標識(id) 的設計不同,核心在于“修改操作是否改變對象的內存地址”。

1. 核心概念:id、value、type

在Python中,每個對象都有三個核心屬性:

  • id:對象的唯一身份標識,對應內存地址(通過id()函數(shù)查看);
  • value:對象的實際數(shù)據(jù)(如10、"Python"、[1,2,3]);
  • type:對象的類型(通過type()函數(shù)查看)。

兩類對象的關鍵差異:

  • 不可變對象idvalue綁定,value一旦確定,id就固定;修改value必須創(chuàng)建新對象(新id);
  • 可變對象id與“容器本身”綁定,value(容器內的數(shù)據(jù))可修改,且修改后id不變。

2. 內存存儲示意(直觀理解)

(1)不可變對象(以int為例)

# 初始賦值:a指向id=140708484554720的對象(value=10)
a = 10
內存:a → [id=140708484554720, value=10, type=int]

# “修改”操作:創(chuàng)建新對象(id=140708484554784,value=12),a重新指向新對象
a = a + 2
內存:a → [id=140708484554784, value=12, type=int](原對象10仍存在,等待垃圾回收)

(2)可變對象(以list為例)

# 初始賦值:lst指向id=2524607215232的列表對象(內部存儲[1,2,3])
lst = [1, 2, 3]
內存:lst → [id=2524607215232, value=[1,2,3], type=list]

# 直接修改:列表內部數(shù)據(jù)變?yōu)閇1,2,3,4],但lst仍指向原id
lst.append(4)
內存:lst → [id=2524607215232, value=[1,2,3,4], type=list](id不變,僅value修改)

3. 不可變對象的“緩存機制”(額外知識點)

Python對部分不可變對象(如小整數(shù)、短字符串)有緩存機制,即重復創(chuàng)建相同值的對象時,會復用已有的對象(避免頻繁創(chuàng)建銷毀,節(jié)省內存)。

# 示例1:小整數(shù)緩存(范圍通常是-5~256)
a = 10
b = 10
print(id(a) == id(b))  # 輸出:True(復用同一對象)

c = 1000
d = 1000
print(id(c) == id(d))  # 輸出:False(超出小整數(shù)范圍,創(chuàng)建新對象)

# 示例2:短字符串緩存(字符串駐留機制)
s1 = "Python"
s2 = "Python"
print(id(s1) == id(s2))  # 輸出:True(復用同一對象)

s3 = "Python123"
s4 = "Python123"
print(id(s3) == id(s4))  # 輸出:True(短字符串通常會被緩存)

s5 = "Python " + "123"  # 動態(tài)拼接的字符串,是否緩存取決于解釋器
print(id(s5) == id(s3))  # 輸出:False(動態(tài)拼接未觸發(fā)緩存)

注意:緩存機制是Python的內部優(yōu)化,開發(fā)者不應依賴此特性(如不能通過id判斷兩個不可變對象的值是否相等,應直接用==比較值)。

三、核心差異對比:從賦值、傳參到使用場景

兩類對象在變量賦值函數(shù)傳參、使用場景上的差異,是開發(fā)中最容易踩坑的地方,用表格直觀對比:

對比維度

不可變對象(如int、str、tuple)

可變對象(如list、dict、set)

賦值邏輯

新賦值會創(chuàng)建新對象,變量指向新id

新賦值僅讓變量指向原對象(共享引用),修改內部數(shù)據(jù)會影響所有引用

函數(shù)傳參

傳“值的引用”,函數(shù)內修改不會影響外部變量

傳“對象的引用”,函數(shù)內修改會影響外部對象

==is判斷

==比較值,is比較id(緩存可能導致is為True)

==比較值,is比較id(修改后is仍為True)

安全性

線程安全(不可修改,無并發(fā)修改風險)

非線程安全(多線程修改需加鎖)

適用場景

存儲固定數(shù)據(jù)(如配置、常量、字典鍵)

存儲動態(tài)數(shù)據(jù)(如待處理列表、實時更新的字典)

1. 變量賦值:共享引用 vs 獨立對象

(1)不可變對象:賦值創(chuàng)建新對象

a = 10
b = a  # b指向a的對象(id相同)
print(f"a: {a}, id(a): {id(a)}; b: , id(b): {id(b)}")  # 輸出:a:10, id(a):140708484554720; b:10, id(b):140708484554720

a = a + 2  # a指向新對象(id變化)
print(f"a: {a}, id(a): {id(a)}; b: , id(b): {id(b)}")  # 輸出:a:12, id(a):140708484554784; b:10, id(b):140708484554720(b不受影響)

(2)可變對象:賦值共享引用

lst1 = [1, 2, 3]
lst2 = lst1  # lst2與lst1指向同一對象(共享引用)
print(f"lst1: {lst1}, id(lst1): {id(lst1)}; lst2: {lst2}, id(lst2): {id(lst2)}")  # 輸出:lst1:[1,2,3], id(lst1):2524607215232; lst2:[1,2,3], id(lst2):2524607215232

lst1.append(4)  # 修改lst1(共享對象)
print(f"lst1: {lst1}, id(lst1): {id(lst1)}; lst2: {lst2}, id(lst2): {id(lst2)}")  # 輸出:lst1:[1,2,3,4], id(lst1):2524607215232; lst2:[1,2,3,4], id(lst2):2524607215232(lst2同步變化)

2. 函數(shù)傳參:傳值 vs 傳引用(Python的“傳對象引用”機制)

Python的函數(shù)傳參既不是純“傳值”,也不是純“傳引用”,而是 “傳對象引用” ——本質是將變量指向的對象地址(id)傳給函數(shù)參數(shù),參數(shù)與原變量共享同一對象。

(1)不可變對象:函數(shù)內修改不影響外部

def modify_immutable(x):
    x = x + 10  # 創(chuàng)建新對象,參數(shù)x指向新id
    print(f"函數(shù)內x: {x}, id(x): {id(x)}")

a = 5
print(f"調用前a: {a}, id(a): {id(a)}")  # 輸出:調用前a:5, id(a):140708484554560
modify_immutable(a)  # 輸出:函數(shù)內x:15, id(x):140708484554880
print(f"調用后a: {a}, id(a): {id(a)}")  # 輸出:調用后a:5, id(a):140708484554560(a不受影響)

(2)可變對象:函數(shù)內修改影響外部

def modify_mutable(lst):
    lst.append(10)  # 直接修改共享對象
    print(f"函數(shù)內lst: {lst}, id(lst): {id(lst)}")

lst = [1, 2, 3]
print(f"調用前l(fā)st: {lst}, id(lst): {id(lst)}")  # 輸出:調用前l(fā)st:[1,2,3], id(lst):2524607215232
modify_mutable(lst)  # 輸出:函數(shù)內lst:[1,2,3,10], id(lst):2524607215232
print(f"調用后lst: {lst}, id(lst): {id(lst)}")  # 輸出:調用后lst:[1,2,3,10], id(lst):2524607215232(lst被修改)

避坑技巧:若想避免函數(shù)修改外部可變對象,可在函數(shù)內創(chuàng)建對象的副本(如lst.copy()、dict.copy()copy.deepcopy()):

def modify_mutable_safe(lst):
    new_lst = lst.copy()  # 創(chuàng)建副本,修改副本不影響原對象
    new_lst.append(10)
    print(f"函數(shù)內new_lst: {new_lst}")

lst = [1, 2, 3]
modify_mutable_safe(lst)  # 輸出:函數(shù)內new_lst: [1,2,3,10]
print(f"調用后lst: {lst}")  # 輸出:調用后lst: [1,2,3](原對象未修改)

四、實戰(zhàn)場景:如何選擇可變/不可變對象?

兩類對象沒有絕對的“優(yōu)劣”,只有“適用場景”的差異,開發(fā)中需根據(jù)需求選擇:

1. 優(yōu)先用不可變對象的場景

  • 存儲固定不變的數(shù)據(jù):如程序常量(PI = 3.14159)、配置參數(shù)(DB_HOST = "localhost")、字典的鍵(字典鍵必須不可變);
  • 多線程環(huán)境:不可變對象無需擔心并發(fā)修改問題(線程安全);
  • 需要哈希的場景:如集合元素(集合元素必須可哈希,不可變對象通??晒#?。
# 示例:不可變對象作為字典鍵(合法)
config = {
    ("db", "host"): "localhost",  # 元組(不可變)作為鍵
    ("db", "port"): 3306,
    "timeout": 30  # 字符串(不可變)作為鍵
}

# 錯誤示例:列表(可變)不能作為字典鍵
invalid_config = {
    ["db", "host"]: "localhost"  # 報錯:TypeError: unhashable type: 'list'
}

2. 優(yōu)先用可變對象的場景

  • 存儲動態(tài)變化的數(shù)據(jù):如待處理的任務列表(tasks = [])、實時更新的用戶數(shù)據(jù)(user_info = {"name": "張三", "score": 0});
  • 需要頻繁修改內部數(shù)據(jù)的場景:如列表的append()、remove(),字典的update()等操作(無需創(chuàng)建新對象,效率更高);
  • 傳遞復雜數(shù)據(jù)結構并允許修改:如函數(shù)間傳遞列表,允許函數(shù)補充數(shù)據(jù)(需明確告知修改邏輯,避免隱藏BUG)。
# 示例:可變對象存儲動態(tài)數(shù)據(jù)
user_scores = {"張三": 85, "李四": 92}
# 動態(tài)更新分數(shù)(無需創(chuàng)建新字典,直接修改)
user_scores["張三"] = 88  # 覆蓋原分數(shù)
user_scores["王五"] = 79  # 新增數(shù)據(jù)
print(user_scores)  # 輸出:{'張三': 88, '李四': 92, '王五': 79}

# 示例:函數(shù)間傳遞可變對象并協(xié)作修改
def add_task(tasks, task):
    tasks.append(task)  # 直接修改傳入的列表

task_list = ["寫代碼", "測功能"]
add_task(task_list, "修復BUG")
print(task_list)  # 輸出:['寫代碼', '測功能', '修復BUG'](原列表被更新)

五、避坑指南:這些場景最容易出錯!

因對可變/不可變對象理解不清導致的BUG,在開發(fā)中非常常見,以下是高頻坑點及解決方案:

1. 坑點1:可變對象作為函數(shù)默認參數(shù)

問題:函數(shù)默認參數(shù)在定義時僅初始化一次,若默認參數(shù)是可變對象(如列表、字典),多次調用函數(shù)會共享該對象,導致意外累積數(shù)據(jù)。

# 錯誤示例:用列表作為默認參數(shù)
def add_item(item, lst=[]):  # lst在函數(shù)定義時初始化一次
    lst.append(item)
    return lst

print(add_item(1))  # 輸出:[1](首次調用正常)
print(add_item(2))  # 輸出:[1, 2](二次調用復用了同一個列表,意外累積)

解決方案:默認參數(shù)用None代替可變對象,在函數(shù)內初始化:

def add_item(item, lst=None):
    if lst is None:
        lst = []  # 每次調用時重新初始化列表
    lst.append(item)
    return lst

print(add_item(1))  # 輸出:[1]
print(add_item(2))  # 輸出:[2](符合預期)

2. 坑點2:誤修改共享的可變對象

問題:多個變量引用同一可變對象時,修改其中一個變量會影響其他變量,導致數(shù)據(jù)不一致。

# 問題場景:復制列表時直接賦值(共享引用)
user_list = ["張三", "李四", "王五"]
admin_list = user_list  # admin_list與user_list指向同一列表

admin_list.remove("王五")  # 修改admin_list
print(user_list)  # 輸出:['張三', '李四'](user_list也被修改,可能非預期)

解決方案:創(chuàng)建可變對象的副本(淺拷貝/深拷貝),避免共享引用:

# 方案1:淺拷貝(適用于元素為不可變對象的情況)
user_list = ["張三", "李四", "王五"]
admin_list = user_list.copy()  # 列表專用拷貝
# 或 admin_list = list(user_list)
# 或 admin_list = user_list[:]

admin_list.remove("王五")
print(user_list)  # 輸出:['張三', '李四', '王五'](原列表不受影響)

# 方案2:深拷貝(適用于嵌套可變對象的情況,需用copy模塊)
import copy
nested_list = [1, [2, 3], 4]
shallow_copy = nested_list.copy()  # 淺拷貝:內層列表仍共享
deep_copy = copy.deepcopy(nested_list)  # 深拷貝:完全獨立

shallow_copy[1].append(5)
print(nested_list)  # 輸出:[1, [2, 3, 5], 4](淺拷貝影響原對象)
deep_copy[1].append(6)
print(nested_list)  # 輸出:[1, [2, 3, 5], 4](深拷貝不影響原對象)

3. 坑點3:混淆“不可變對象的修改”與“重新賦值”

問題:試圖直接修改不可變對象(如字符串、元組)會報錯,需通過重新賦值生成新對象。

# 錯誤示例:直接修改字符串
s = "Python"
s[0] = "p"  # 報錯:TypeError: 'str' object does not support item assignment

# 錯誤示例:直接修改元組
t = (1, 2, 3)
t[0] = 100  # 報錯:TypeError: 'tuple' object does not support item assignment

解決方案:通過拼接、切片等方式生成新對象,再重新賦值:

# 正確:字符串重新賦值
s = "Python"
s = "p" + s[1:]  # 生成新字符串
print(s)  # 輸出:python

# 正確:元組重新賦值(通過切片生成新元組)
t = (1, 2, 3)
t = (100,) + t[1:]  # 生成新元組
print(t)  # 輸出:(100, 2, 3)

六、總結:理解本質,靈活運用

可變對象與不可變對象的核心差異,在于“修改操作是否改變對象的內存地址(id)”:

  • 不可變對象:修改即創(chuàng)建新對象(id改變),適合存儲固定數(shù)據(jù),線程安全;
  • 可變對象:修改不改變id,適合存儲動態(tài)數(shù)據(jù),操作高效但需注意共享引用問題。

掌握這一本質后,就能理解:

  • 為什么函數(shù)傳參時,列表會被修改而整數(shù)不會;
  • 為什么字典的鍵必須是不可變對象;
  • 為什么默認參數(shù)不能用可變對象。

實際開發(fā)中,沒有“必須用哪種”的絕對規(guī)則,關鍵是根據(jù)場景選擇:需要固定數(shù)據(jù)用不可變對象,需要動態(tài)修改用可變對象,并注意規(guī)避共享引用導致的意外修改。

到此這篇關于python可變/不可變對象及+=和=+的文章就介紹到這了,更多相關python可變/不可變對象及+=和=+內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • Python獲取當前腳本文件夾(Script)的絕對路徑方法代碼

    Python獲取當前腳本文件夾(Script)的絕對路徑方法代碼

    在本篇文章中小編給各位整理了關于Python獲取當前腳本文件夾(Script)的絕對路徑實例代碼內容,有需要的朋友們學習下。
    2019-08-08
  • 最新python 字符串數(shù)組互轉問題

    最新python 字符串數(shù)組互轉問題

    這篇文章主要介紹了最新python 字符串數(shù)組互轉問題,主要介紹了字符串轉list數(shù)組問題和list數(shù)組轉字符串問題,本文結合示例代碼給大家介紹的非常詳細,需要的朋友可以參考下
    2023-02-02
  • Python身份運算符(is/is not)與雙等號的區(qū)別詳解

    Python身份運算符(is/is not)與雙等號的區(qū)別詳解

    身份運算符(is/is not)與雙等號的區(qū)別是Python編程中的核心知識點之一,掌握這項技能對于提升編程效率和應用效果至關重要,本文通過代碼示例給大家介紹的非常詳細,需要的朋友可以參考下
    2026-05-05
  • python發(fā)送郵件示例(支持中文郵件標題)

    python發(fā)送郵件示例(支持中文郵件標題)

    python發(fā)送中文郵件示例,支持中文郵件標題和中文郵件內容。支持多附件。根據(jù)用戶名推測郵件服務器提供商
    2014-02-02
  • python中循環(huán)語句while用法實例

    python中循環(huán)語句while用法實例

    這篇文章主要介紹了python中循環(huán)語句while用法,實例分析了while語句的使用方法,需要的朋友可以參考下
    2015-05-05
  • 詳解Python裝飾器由淺入深

    詳解Python裝飾器由淺入深

    裝飾器的功能在很多語言中都有,名字也不盡相同,其實它體現(xiàn)的是一種設計模式,強調的是開放封閉原則,更多的用于后期功能升級而不是編寫新的代碼。本文盡量描述得淺顯易懂,從最基礎的內容講起。
    2016-12-12
  • 詳解Python中的?type()函數(shù)

    詳解Python中的?type()函數(shù)

    type()是一個內置函數(shù),可以很方便地查詢對象數(shù)據(jù)類型;主要有兩種用法:一個參數(shù)和三個參數(shù),這篇文章主要介紹了Python中的?type()函數(shù),需要的朋友可以參考下
    2022-08-08
  • python密碼學RSA密碼加密教程

    python密碼學RSA密碼加密教程

    這篇文章主要為大家介紹了python密碼學RSA密碼加密教程,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-05-05
  • Google開源的Python格式化工具YAPF的安裝和使用教程

    Google開源的Python格式化工具YAPF的安裝和使用教程

    Google的開發(fā)者文檔中有一套Python的代碼書寫規(guī)范,而在GitHub上同樣開源了一款名為YAPF的命令行程序用作Python的格式化,下面我們就來看下這款Google開源的Python格式化工具YAPF的安裝和使用教程
    2016-05-05
  • 利用python畫出AUC曲線的實例

    利用python畫出AUC曲線的實例

    今天小編就為大家分享一篇利用python畫出AUC曲線的實例,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-02-02

最新評論

团风县| 双桥区| 勐海县| 竹溪县| 皋兰县| 习水县| 察哈| 绍兴市| 全州县| 安泽县| 海盐县| 古交市| 灌南县| 全椒县| 阳原县| 五原县| 启东市| 大厂| 武川县| 体育| 平遥县| 盘锦市| 灯塔市| 峨眉山市| 海晏县| 孟连| 蒲城县| 重庆市| 历史| 望城县| 政和县| 扶沟县| 肥东县| 浙江省| 佛教| 漳平市| 都江堰市| 于都县| 三穗县| 三门县| 株洲县|