Python基礎(chǔ)學(xué)習(xí)之深淺拷貝問題及遞歸函數(shù)練習(xí)
一、深淺拷貝問題
在實(shí)際工作中,經(jīng)常涉及到數(shù)據(jù)的傳遞,在數(shù)據(jù)傳遞使用過程中,可能會(huì)發(fā)生數(shù)據(jù)被修改的問題。為了防止數(shù)據(jù)被修改,就需要在傳遞一個(gè)副本,即使副本被修改,也不會(huì)影響原數(shù)據(jù)的使用。為了生成這個(gè)副本,就產(chǎn)生了拷貝。下面先了解一下幾個(gè)概念:對(duì)象、可變類型、引用
Python對(duì)象:在 Python 中,對(duì)象有一種很通俗的說法是,萬物皆對(duì)象。說的就是構(gòu)造的任何數(shù)據(jù)類型都是一個(gè)對(duì)象,無論是數(shù)字,字符串,還是函數(shù),甚至是模塊,Python都對(duì)當(dāng)做對(duì)象處理。所有 Python 對(duì)象都擁有三個(gè)屬性:身份、類型、值。看一個(gè)簡(jiǎn)單的例子:

可變與不可變對(duì)象:在Python中,按更新對(duì)象的方式,可以將對(duì)象分為 2 大類:可變對(duì)象與不可變對(duì)象。
- 可變對(duì)象: 列表、字典、集合,所謂可變是指可變對(duì)象的值可變,身份是不變的。
- 不可變對(duì)象:數(shù)字、字符串、元組,不可變對(duì)象就是對(duì)象的身份和值都不可變。新創(chuàng)建的對(duì)象被關(guān)聯(lián)到原來的變量名,舊對(duì)象被丟棄,垃圾回收器會(huì)在適當(dāng)?shù)臅r(shí)機(jī)回收這些對(duì)象。

引用:在 Python 程序中,每個(gè)對(duì)象都會(huì)在內(nèi)存中申請(qǐng)開辟一塊空間來保存該對(duì)象,該對(duì)象在內(nèi)存中所在位置的地址被稱為引用。在開發(fā)程序時(shí),所定義的變量名實(shí)際就對(duì)象的地址引用。
引用實(shí)際就是內(nèi)存中的一個(gè)數(shù)字地址編號(hào),在使用對(duì)象時(shí),只要知道這個(gè)對(duì)象的地址,就可以操作這個(gè)對(duì)象,但是因?yàn)檫@個(gè)數(shù)字地址不方便在開發(fā)時(shí)使用和記憶,所以使用變量名的形式來代替對(duì)象的數(shù)字地址。 在 Python 中,變量就是地址的一種表示形式,并不開辟開辟存儲(chǔ)空間。
就像 IP 地址,在訪問網(wǎng)站時(shí),實(shí)際都是通過 IP 地址來確定主機(jī),而 IP 地址不方便記憶,所以使用域名來代替 IP 地址,在使用域名訪問網(wǎng)站時(shí),域名被解析成 IP 地址來使用。
通過一個(gè)例子來說明變量和變量指向的引用:

- 基本類型和引用類型數(shù)據(jù)拷貝的問題。因?yàn)榛绢愋偷臄?shù)據(jù)大小是固定的,所以他保存在棧內(nèi)存中;而引用類型的數(shù)據(jù)大小不固定,因而保存在堆內(nèi)存中,單引用類型在棧內(nèi)存中只保存一個(gè)指向堆內(nèi)存的指針。
- 淺拷貝:對(duì)于淺拷貝來說,如果拷貝基本類型,那么就等于賦值一樣,會(huì)直接拷貝其本身;但如果拷貝的是引用類型,就只會(huì)拷貝一層,如果原對(duì)象發(fā)生改變,那么拷貝對(duì)象也會(huì)發(fā)生改變。
- 深拷貝:深拷貝的話就會(huì)拷貝多層,嵌套的對(duì)象也會(huì)被拷貝出來,相當(dāng)于開辟一個(gè)新的內(nèi)存地址用于存放拷貝的對(duì)象。在 python 語言中沒有明顯的指出,例如,操作指針或?qū)τ谥羔樀牟僮鳌?/li>

- 拷貝就是一個(gè)變量的值傳給另外一個(gè)變量。在 python 中 id() 方法可以查看存放變量的內(nèi)存地址,這為我們下面理解深淺 copy 提供了便利。
- 淺拷貝是指把存放變量的地址值傳給被賦值,最后兩個(gè)變量引用了同一份地址,如上圖所示。
- 深拷貝是指被賦值的變量開辟了另一塊地址用來存放要賦值的變量的值(內(nèi)容)。在 python 中引用 copy 模塊,copy模塊中有 deepcopy() 方法,調(diào)用它完成變量的深copy,觀察變量地址如下:

淺拷貝只拷貝頂層引用,遇到引用類型,只是復(fù)制了個(gè)引用,修改了副本中引用類型里的數(shù)據(jù),原數(shù)據(jù)也會(huì)改變,示例如下:


深拷貝會(huì)逐層進(jìn)行拷貝,直到拷貝的所有引用都是不可變引用為止,示例如下:

lst1 = [1, [6, 7, 8], 3]
lst1
# [1, [6, 7, 8], 3]
lst2 = copy.deepcopy(lst1)
lst2
# [1, [6, 7, 8], 3]
lst2[1][1] = 996
print("副本:", lst2)
print("原始:", lst1)
# 副本: [1, [6, 996, 8], 3]
# 原始: [1, [6, 7, 8], 3]

在深拷貝中,修改了副本中引用類型里的數(shù)據(jù),原數(shù)據(jù)不會(huì)改變。
總結(jié)如下:
- Python默認(rèn)的拷貝方式是淺拷貝:因?yàn)闇\拷貝花費(fèi)時(shí)間更少、花費(fèi)內(nèi)存更少、淺拷貝只拷貝頂層數(shù)據(jù),一般情況下比深拷貝效率高。大多數(shù)情況下,編寫程序時(shí),都是使用淺拷貝,除非有特定的需求。
- Python中有多種方式實(shí)現(xiàn)淺拷貝,copy模塊的 copy 函數(shù) ,對(duì)象的 copy 函數(shù) ,工廠方法,切片等。
- 不可變對(duì)象在賦值時(shí)會(huì)開辟新空間;可變對(duì)象在賦值時(shí),修改一個(gè)的值,另一個(gè)也會(huì)發(fā)生改變。深、淺拷貝對(duì)不可變對(duì)象拷貝時(shí),不開辟新空間,相當(dāng)于賦值操作。
- 淺拷貝在拷貝時(shí),只拷貝第一層中的引用,如果元素是可變對(duì)象,并且被修改,那么拷貝的對(duì)象也會(huì)發(fā)生變化;深拷貝在拷貝時(shí),會(huì)逐層進(jìn)行拷貝,直到所有的引用都是不可變對(duì)象為止。
二、遞歸函數(shù)練習(xí)
1. 求階乘
def factorial(n):
return 1 if n == 1 else n * factorial(n - 1)
factorial(5)
結(jié)果如下:

2. 猴子吃桃問題
猴子第一天摘下若干個(gè)桃子,當(dāng)即吃了一半,還不癮,又多吃了一個(gè)。第二天早上又將剩下的桃子吃掉一半,又多吃了一個(gè)。以后每天早上都吃了前一天剩的一半零一個(gè)。到第 10 天早上想再吃時(shí),見只剩下一個(gè)桃子了,求第一天共摘了多少桃子?
# 第10天早上想再吃時(shí),見只剩下一個(gè)桃子了,說明第9天的時(shí)候就只剩一個(gè)桃子了
def eat_peach(n):
return 1 if n == 2 else 2 * (eat_peach(n - 1) + 1)
eat_peach(10)
結(jié)果如下:

3. 打印斐波那契數(shù)列
# -*- coding: UTF-8 -*-
"""
@Author :葉庭云
@CSDN :https://yetingyun.blog.csdn.net/
"""
def fibonacii(n):
return n if n <= 1 else (fibonacii(n - 1) + fibonacii(n - 2))
x = int(input("輸出前幾項(xiàng)?: "))
if x <= 0:
print("請(qǐng)輸入輸入正數(shù)!")
else:
print("斐波那契數(shù)列前{}項(xiàng):".format(x), end=" ")
for i in range(1, x + 1):
print(fibonacii(i), end=" ")
結(jié)果如下:?

到此這篇關(guān)于Python基礎(chǔ)學(xué)習(xí)之深淺拷貝問題及遞歸函數(shù)練習(xí)的文章就介紹到這了,更多相關(guān)Python 深淺拷貝 遞歸函數(shù)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Python學(xué)習(xí)筆記之迭代器和生成器用法實(shí)例詳解
這篇文章主要介紹了Python學(xué)習(xí)筆記之迭代器和生成器用法,結(jié)合實(shí)例形式詳細(xì)分析了Python迭代器與生成器的功能、原理、定義及使用方法,需要的朋友可以參考下2019-08-08
Python實(shí)現(xiàn)嵌套列表的7中方法總結(jié)
這篇文章主要來給大家講解一個(gè)Python的進(jìn)階知識(shí)點(diǎn):如何將一個(gè)嵌套的大列表展開形成一個(gè)列表。小編提供了7種方法供大家學(xué)習(xí)參考,希望大家能喜歡2023-03-03
python如何使用pywebview打造一個(gè)現(xiàn)代化的可視化GUI界面詳解
pywebview是一個(gè)輕量級(jí)的跨平臺(tái)庫,它可以讓你在Python程序中嵌入一個(gè)瀏覽器窗口,下面這篇文章主要給大家介紹了關(guān)于python如何使用pywebview打造一個(gè)現(xiàn)代化的可視化GUI界面的相關(guān)資料,需要的朋友可以參考下2024-07-07
使用Python解析JSON數(shù)據(jù)的基本方法
這篇文章主要介紹了使用Python解析JSON數(shù)據(jù)的基本方法,是Python入門學(xué)習(xí)中的基礎(chǔ)知識(shí),需要的朋友可以參考下2015-10-10
詳解Python實(shí)現(xiàn)字典合并的四種方法
這篇文章主要為大家詳細(xì)介紹了Python的合并字典的四種方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助2022-03-03
django 解決manage.py migrate無效的問題
今天小編就為大家分享一篇django 解決manage.py migrate無效的問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2018-05-05
Django調(diào)用百度AI接口實(shí)現(xiàn)人臉注冊(cè)登錄代碼實(shí)例
這篇文章主要介紹了Django調(diào)用百度AI接口實(shí)現(xiàn)人臉注冊(cè)登錄,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-04-04

