【Python學習】——語言風格(變量賦值、深淺拷貝、for循環陷阱)

目錄

1、賦值

?2、賦值的分類——引用賦值、值賦值

1) 不可變對象引用賦值——字符串、數值、元組等

2)可變對象引用賦值——列表、集合、字典

3)可變與不可變對象的引用賦值內部分析

4)在py文件中,和作用域有關,如在同一個函數中的相同值的變量是相等的,即值相等,地址也相等

3、深拷貝與淺拷貝

4、循環——序列和非序列的循環中進行元素的修改


?

1、賦值

# 賦值包含多種賦值方式,一般賦值、元組賦值、序列賦值、解包賦值
a = "long"
b,c = "1",2
d,e,f,g = "long"
h,*i = "long"
print(a)
print(b)
print(c)
print(d)
print(e)
print(f)
print(g)
print(h)
print(i)

long
1
2
l
o
n
g
l
['o', 'n', 'g']

當使用一個*前綴變量的時候,表示將序列對應的元素全部收集到一個列表中(注意,總是一個列表),這個列表名為*開頭的那個變量名。*號可以出現在任意位置處,只要賦值的時候能前后對應位置關系即可。

注意其中的幾個關鍵字:序列、對應的元素、列表

  • 序列意味著可以是列表、元組、字符串等等
  • 列表意味著只要收集不報錯,賦值給解包變量的一定是一個列表
  • 對應的元素意味著可能收集到0或任意個元素到列表。

不管如何,收集的結果總是列表,只不過可能是空列表或者只有一個元素的列表。

?

兩個注意事項:

  1. 因為序列解包是根據元素位置來進行賦值的,所以不能出現多個解包變量
  2. 如果將序列直接賦值給單個解包變量時(即沒有普通變量),這個解包變量必須放在列表或元組中
a,*b,c,*d = L     # 錯誤
*a = L            # 錯誤
[*a] = L          # 正確
(*a) = L          # 正確

?2、賦值的分類——引用賦值、值賦值

引用賦值——指的是將內存地址賦值給變量來實現賦值

1) 不可變對象引用賦值——字符串、數值、元組等

a = 1000

b = a

a = 2000

前兩行b=a是將1000的地址賦值給b,即a和b都是指向值1000的內存地址。第三行a=2000是對a重新進行賦值,因為數值是不可改變的對象,因此會先開辟一個內存地址用于存儲2000,然后將a指向2000

不可變對象變量之間不會互相影響,即如果一開始兩個變量指向同一個內存地址,當其中一個變量的值發生了改變的時候,另一個變量不會受到影響

對于不可變對象,修改變量的值意味著在內存中要新創建一個數據對象

a = 10000
b = a
a = 20000>>> a,b
(20000, 10000)

2)可變對象引用賦值——列表、集合、字典

對于可變對象,比如列表,它是在"原處修改"數據對象的(注意加了雙引號)。比如修改列表中的某個元素,列表的地址不會變,還是原來的那個內存對象,所以稱之為"原處修改"。例如:

L1 = [111,222,333]
L2 = L1
L1[1] = 2222>>> L1,L2
([111, 2222, 333], [111, 2222, 333])

L2是通過引用賦值得到的值,值為可變對象列表,當對L1改變一個列表元素時,其列表的地址不會發生改變,因此其L2的值也會發生相應的改變

L1[1]賦值的前后,數據對象[111,222,333]的地址一直都沒有改變,但是這個列表的第二個元素的值已經改變了。因為L1和L2都指向這個列表,所以L1修改第二個元素后,L2的值也相應地到影響。也就是說,L1和L2仍然是同一個列表對象[111,2222,333]

結論是:對于可變對象,變量之間是相互影響的

3)可變與不可變對象的引用賦值內部分析

可變對象和不可變對象的賦值形式雖然一樣,但是修改數據時的過程不一樣。

對于不可變對象,修改數據是直接在堆內存中新創建一個數據對象。如圖:

對于可變對象,修改這個可變對象中的元素時,這個可變對象的地址不會改變,所以是"原處修改"的。但需要注意的是,這個被修改的元素可能是不可變對象,可能是可變對象,如果被修改的元素是不可變對象,就會創建一個新數據對象,并引用這個新數據對象,而原始的那個元素將等待垃圾回收器回收。

>>> L=[333,444,555]
>>> id(L),id(L[1])
(56583832, 55771984)
>>> L[1]=4444
>>> id(L),id(L[1])
(56583832, 55771952)

如圖所示:

4)在py文件中,和作用域有關,如在同一個函數中的相同值的變量是相等的,即值相等,地址也相等

3、深拷貝與淺拷貝

1)深拷貝

完全創建一個新的數據對象,不會受到其他變量的元素值變化的影響

2)淺拷貝,只是拷貝了第一層的元素,若第一層的元素是可變對象,則引用的是可變對象的地址,因此還是會受到其他變量的影響

# 引用賦值——只是得到了地址
print("賦值----------------------")
L = [1,2,[3,4,5]]
L2 = L
print("修改元素前-----------")
print(L)
print(L2)
print("修改元素后-----------")
L[0] = 0
print(L)
print(L2)

賦值----------------------
修改元素前-----------
[1, 2, [3, 4, 5]]
[1, 2, [3, 4, 5]]
修改元素后-----------
[0, 2, [3, 4, 5]]
[0, 2, [3, 4, 5]]?

print("淺拷貝------------------------")print("淺拷貝1------------------------")
# 淺拷貝——只是拷貝了第一層的元素,若為不可變元素,則會重新為元素創建一個新的數據對象,若為可變數據對象,則只是拷貝了地址
L = [1,2,[3,4,5],6]
L1 = L.copy()
print("修改不可變對象的元素前-----------")
print(L)
print(L1)
print("修改不可變對象的元素后-----------")
L[0] = 0
print(L)
print(L1)print("淺拷貝1------------------------")
L = [1,2,[3,4,5],6]
L1 = L.copy()
print("修改可變對象的元素前-----------")
print(L)
print(L1)
print("修改可變對象的元素后-----------")
L[2][0] = 0
print(L)
print(L1)print("淺拷貝2------------------------")
L = [1,2,[3,4,5]]
L3 = L[:]
print("修改元素前-----------")
print(L)
print(L3)
print("修改元素后-----------")
L[0] = 0
L[2][0] = 0
print(L)
print(L3)

?

淺拷貝------------------------
淺拷貝1------------------------
修改不可變對象的元素前-----------
[1, 2, [3, 4, 5], 6]
[1, 2, [3, 4, 5], 6]
修改不可變對象的元素后-----------
[0, 2, [3, 4, 5], 6]
[1, 2, [3, 4, 5], 6]
淺拷貝1------------------------
修改可變對象的元素前-----------
[1, 2, [3, 4, 5], 6]
[1, 2, [3, 4, 5], 6]
修改可變對象的元素后-----------
[1, 2, [0, 4, 5], 6]
[1, 2, [0, 4, 5], 6]
淺拷貝2------------------------
修改元素前-----------
[1, 2, [3, 4, 5]]
[1, 2, [3, 4, 5]]
修改元素后-----------
[0, 2, [0, 4, 5]]
[1, 2, [0, 4, 5]]

from copy import deepcopy
print("深拷貝------------------------")
L = [1,2,[3,4,5]]
L1 = deepcopy(L)
L[0] = 0
L[2][0] = 0
print(L)
print(L1)

深拷貝------------------------
[0, 2, [0, 4, 5]]
[1, 2, [3, 4, 5]]

一般我們使用到的都是淺拷貝

4、循環——序列和非序列的循環中進行元素的修改

https://www.cnblogs.com/f-ck-need-u/p/10129317.html

1)列表進行原地修改時(L+=[val1,val2]),進行后面的迭代時,進行迭代的是修改后的列表,因為for是一個迭代器,使用的是next,即通過索引進行的,因此列表原地修改會導致元素出現奇怪的現象

為了避免這種情況,我們對列表進行修改時,建議生成一個新的列表對象來進行存放

L = ['a','b','c','d','e']## 原處修改列表,新元素f、g也會被迭代
for i in L:if i in "de":L += ["f", "g"]print(i)## 創建新列表,新元素f、g不會被迭代
for i in L:if i in "de":L = L + ["f", "g"]print(i)

這個for迭代器在迭代剛開始的時候,先找到L所指向的迭代對象,即內存中的[1,2,3,4]。如果迭代過程中如果L變成了一個集合,或另一個列表對象,for的迭代并不會收到影響。但如果是在原處修改這個列表,那么迭代將會收到影響,例如新增元素也會被迭代到。

這里通過列表索引來進行元素的遍歷和修改即可避免上面的情況

2)迭代一個列表,迭代過程中刪除一個列表元素。

L = ['a','b','c','d','e']
for i in L:if i in "bc":L.remove(i)print(i)print(L)

輸出的結果將是:

b
['a', 'c', 'd', 'e']

這個for循環的本意是想刪除b、c元素,但結果卻只刪除了b。通過結果可以發現,c根本就沒有被for迭代。之所以會這樣,是因為迭代到b的時候,滿足if條件,然后刪除了列表中的b元素。正因為刪除操作,使得列表中b后面的元素整體前移一個位置,也就是c元素的索引位置變成了index=1,而index=1的元素已經被for迭代過(即元素b),使得c幸運地逃過了for的迭代。

3)迭代的是字典或者集合時,雖然兩者都是可變序列,但是時無序的,因此在迭代的過程中,是不允許字典或者集合發生改變的,否則會報錯

D = {'a':1,'b':2,'c':3,'d':4,'e':5}for i in D:if i in "bc":del D[i]print(i)print(D)

報錯:

b
Traceback (most recent call last):File "g:/pycode/lists.py", line 12, in <module>for i in D:
RuntimeError: dictionary changed size during iteration
S = {'a','b','c','d','e'}for i in S:if i in "bc":S.remove(i)print(i)print(S)

報錯:

b
Traceback (most recent call last):File "g:/pycode/lists.py", line 4, in <module>for i in L:
RuntimeError: Set changed size during iteration

若想修改字典的話,我們可以復制一份數據對象作為副本,然后將副本進行迭代,將原來的字典或集合作為修改對象?

D = {'a':1,'b':2,'c':3,'d':4,'e':5}for i in D.copy():if i in "bc":D.pop(i)print(i)
print(D)S = {'a','b','c','d','e'}for i in S.copy():if i in "bc":S.remove(i)print(i)
print(S)

?注意:在進行可變對象數據對象的迭代與修改時,我們只需要將迭代對象和修改對象分開就不會出現上述的錯誤。

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

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

相關文章

underscore.js 頁面數據渲染

1.underscore.js 源碼 // Underscore.js 1.8.3 // http://underscorejs.org // (c) 2009-2015 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors // Underscore may be freely distributed under the MIT license.(function() {// …

判斷莊家是否出貨

1. 大盤處于強勢的時候 日平均線在橫盤的時候&#xff0c;緩慢拉升然后急劇下跌 高位盤整的時候 2. 有利好消息發布的時候 因為莊家會利用這個對于散戶來說這個買入時機來進行出貨操作&#xff0c;可見莊家真是陰險狡詐轉載于:https://www.cnblogs.com/dcz1001/p/6115893.html

【深度學習】——常見深度學習模型總結、anchor-free和anchor-based

目錄 1、faster rcnn&#xff1a; 2、SSD&#xff1a; 3、YOLOv1: 小結&#xff1a; 拓展&#xff1a;anchor-based和anchor-free anchor 1、faster rcnn&#xff1a; FasterRcnn 算法原理講解筆記&#xff08;非常詳細&#xff09;https://blog.csdn.net/xjtdw/article…

PHP PDO函數庫詳解

PDO是一個“數據庫訪問抽象層”&#xff0c;作用是統一各種數據庫的訪問接口&#xff0c;與mysql和mysqli的函數庫相比&#xff0c;PDO讓跨數據庫的使用更具有親和力&#xff1b;與ADODB和MDB2相比&#xff0c;PDO更高效。目前而言&#xff0c;實現“數據庫抽象層”任重而道遠&…

數據交互相關分享

Python與web Python Web.py與AJAX交互轉載于:https://juejin.im/post/5a40af3d6fb9a044ff31b1f5

springMVC 相對于 Structs 的優勢

智者說&#xff0c;沒有經過自己的思考和估量&#xff0c;就不能接受別人的東西。資料只能是一個參考&#xff0c;至于是否正確&#xff0c;還得自己去分辨 SpringMVC相對于Structs的幾個優勢&#xff1a; 1、springMVC安全性更高&#xff0c;structs2框架是類級別的攔截&#…

YOLOV1學習

YOLOV1學習&#xff08;輸入的圖像固定大小為448X448X3&#xff09; 參考文獻 模型結構 將輸入的圖像歸一化為大小為448x448x3的圖像&#xff0c;然后將經過中間24層的卷積后得到了7x7x1024的特征圖&#xff0c;然后后面連接的是兩個全連接層&#xff0c;分別是4096和1470&am…

KUKA通信 CREAD問題

嗨。 我想通過串行端口1發送X&#xff0c;Y&#xff0c;Z&#xff0c;A&#xff0c;B&#xff0c;C坐標給機器人。 G1: ...... CREAD(HANDLE,SR_T,MR_T,TIMEOUT,OFFSET,"%F",X) P.XX CREAD(HANDLE,SR_T,MR_T,TIMEOUT,OFFSET,"%F",Y) P.YY ...... GOTO G1…

bzoj 1901: Zju2112 Dynamic Rankings

Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 6245 Solved: 2593[Submit][Status][Discuss]Description 給定一個含有n個數的序列a[1],a[2],a[3]……a[n]&#xff0c;程序必須回答這樣的詢問&#xff1a;對于給定的i,j,k&#xff0c;在a[i],a[i1],a[i2]……a[j]中第k小的…

第 36 章 RRDTool

36.1. install $ apt-get install rrdtool原文出處&#xff1a;Netkiller 系列 手札 本文作者&#xff1a;陳景峯 轉載請與作者聯系&#xff0c;同時請務必標明文章原始出處和作者信息及本聲明。

手機號碼已經注冊寫到數據庫中,如何利用相同手機號碼再次注冊?

手機號碼已經注冊寫到數據庫中&#xff0c;如何利用相同手機號碼再次注冊&#xff1f; 解&#xff1a;刪除數據庫中以前注冊的手機號碼就可以了啊&#xff0c;delete那條記錄&#xff0c;轉載于:https://www.cnblogs.com/panxuejun/p/6122499.html

騰訊技術研究類和數據分析第一次筆試(2021.8.22)——Python

第一題&#xff1a;開鎖——數學期望 # 最優策略&#xff1a;鑰匙的選擇先從消耗時間最少的開始選擇&#xff0c;然后選擇第二小的依次類推 # 開鎖概率1/n def openLockTime(n, m, time):time_reverse [] # (n,m)->(m,n)for i in range(m):m_time []for j in range(n):m…

教你怎樣選擇伺服電機控制方式

伺服電機一般都有三種控制方式&#xff1a;速度控制方式&#xff0c;轉矩控制方式&#xff0c;位置控制方式 。 速度控制和轉矩控制都是用模擬量來控制的。位置控制是通過發脈沖來控制的。具體采用什么控制方式要根據客戶的要求&#xff0c;滿足何種運動功能來選擇。 …

.Net Discovery系列之四 深入理解.Net垃圾收集機制(下)

上一節給大家介紹了 .Net GC的運行機制&#xff0c;下面來講下與GC相關的重要方法。 第二節&#xff0e;GC關鍵方法解析 1.Dispose()方法 Dispose可用于釋放所有資源&#xff0c;包括托管的和非托管的&#xff0c;需要自己實現。 大多數的非托管資源都要求手動釋放&#xff0c;…

真靜態和偽靜態的區別

首先肯定的是純靜態和偽靜態都是SEO的產物&#xff0c;但純靜態和偽靜態還是有很大區別的。 純靜態是生成真實的HTML頁面保存到服務器端&#xff0c;用戶訪問時直接訪問這 個HTML頁面即可&#xff0c;從而大大的減輕了服務器壓力&#xff08;如dedecms就是采用的純靜態&#xf…

非常有趣的Console

console覺醒之路&#xff0c;打印個動畫如何&#xff1f; 原文地址: http://www.helloweba.com/view-blog-383.html 批量去掉或替換文本中的換行符&#xff08;notepad、sublime text2&#xff09; 原文地址&#xff1a;http://m.blog.csdn.net/article/details?id43228729 有…

shopee蝦皮科技測試工程師第一次筆試

10道單選題 10道多選題 2道編程題 第一題&#xff1a;十進制轉二進制計算1的個數&#xff08;負數轉為補碼&#xff09; #!/usr/bin/env python # -*- coding: utf-8 -*- # Time : 2021/8/23 15:44 # Author : linlianqin # Site : # File : 十進制轉換為二進制&am…

假期實踐

第一天 地點:杭州頤高數碼城 第一天&#xff0c;我來到了自己家附近的頤高數碼城。文三路這邊有一個賣數碼產品的一條街&#xff0c;這里也是最貼近我專業實踐的地方&#xff0c;所以第一天的實踐我選擇了這里。 2001年開業的頤高數碼廣場座落于“電子一條街”文三路、學院路口…

3.AngularJS-過濾器

轉自&#xff1a;https://www.cnblogs.com/best/p/6225621.html 二、過濾器 使用過濾器格式化數據&#xff0c;變換數據格式&#xff0c;在模板中使用一個插值變量。語法格式如下&#xff1a; {{ express | filter:parameter1:p2:p3… | … | …}} 過濾器分了內置過濾器與自定義…

webstorm卡頓問題

解決webstorm卡頓問題 webstorm強大的功能就不多做介紹了。但是它的缺點也顯而易見&#xff1a;吃內存。 電腦配置稍低一點&#xff0c;運行webstorm就特別容易卡頓&#xff0c;特別是項目比較大的時候&#xff0c;那卡頓得不要不要的。 在我的筆記本8g內存 256ssd的配置下&…