溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

使用id()理解Python中的6個(gè)關(guān)鍵概念分別是怎樣的

發(fā)布時(shí)間:2021-10-28 16:14:38 來源:億速云 閱讀:112 作者:柒染 欄目:編程語言

這期內(nèi)容當(dāng)中小編將會(huì)給大家?guī)碛嘘P(guān)使用id()理解Python中的6個(gè)關(guān)鍵概念分別是怎樣的,文章內(nèi)容豐富且以專業(yè)的角度為大家分析和敘述,閱讀完這篇文章希望大家可以有所收獲。

啟動(dòng)任何Python解釋器時(shí),都有70多個(gè)內(nèi)置函數(shù)可用。 每個(gè)Python學(xué)習(xí)者都不應(yīng)不熟悉一些普通的學(xué)習(xí)者。  例如,我們可以使用len()來獲取對(duì)象的長(zhǎng)度,例如列表或字典中的項(xiàng)目數(shù)。 再舉一個(gè)例子,我們可以使用print()打印出感興趣的對(duì)象,以進(jìn)行學(xué)習(xí)和調(diào)試。

此外,幾乎所有Python程序員都應(yīng)該在教程中看到內(nèi)置的id()函數(shù)的使用,以用于指導(dǎo)特定的Python概念。 但是,據(jù)我所知,這些信息是分散的。  在本文中,我想對(duì)使用id()函數(shù)理解六個(gè)關(guān)鍵Python概念進(jìn)行系統(tǒng)的回顧。

1. 一切都是Python中的對(duì)象

作為一種流行的面向?qū)ο蟮木幊陶Z言,Python在其實(shí)現(xiàn)中隨處使用對(duì)象。 例如,諸如整數(shù),浮點(diǎn)數(shù),字符串,列表和字典之類的內(nèi)置數(shù)據(jù)類型都是對(duì)象。  而且,函數(shù),類甚至模塊也被用作對(duì)象。

根據(jù)定義,id()函數(shù)接受一個(gè)對(duì)象并返回該對(duì)象的標(biāo)識(shí),即以整數(shù)表示的內(nèi)存地址。 因此,我們可以使用此函數(shù)來證明Python中的所有對(duì)象都是真實(shí)的。

>>> import sys >>> class Foo: ...     pass ...  >>> def foo(): ...     pass ...  >>> a_tuple = ('Error', 404) >>> a_dict = {'error_code': 404} >>> a_list = [1, 2, 3] >>> a_set = set([2, 3, 5]) >>> objects = [2, 2.2, 'hello', a_tuple, a_dict, a_list, a_set, Foo, foo, sys] >>>  >>> for item in objects: ...     print(f'{type(item)} with id: {id(item)}') ...  <class 'int'> with id: 4479354032 <class 'float'> with id: 4481286448 <class 'str'> with id: 4483233904 <class 'tuple'> with id: 4483061152 <class 'dict'> with id: 4483236000 <class 'list'> with id: 4483236720 <class 'set'> with id: 4483128688 <class 'type'> with id: 140235151304256 <class 'function'> with id: 4483031840 <class 'module'> with id: 4480703856

在上面的代碼片段中,您可以看到對(duì)象列表中的每個(gè)項(xiàng)目都可以在id()函數(shù)中使用,該函數(shù)顯示每個(gè)對(duì)象的內(nèi)存地址。

我認(rèn)為很有趣的以下操作是,作為函數(shù)本身,id()函數(shù)也應(yīng)具有其內(nèi)存地址。

>>> print(f'{type(id)} with id: {id(id)}') <class 'builtin_function_or_method'> with id: 4480774224

2. 變量分配和別名

在Python中創(chuàng)建變量時(shí),通常使用以下語法:

var_name = the_object

此過程基本上將在內(nèi)存中創(chuàng)建的對(duì)象綁定到特定的變量名稱。 如果為變量分配另一個(gè)變量,例如var_name1 = var_name,會(huì)發(fā)生什么?

考慮以下示例。 在下面的代碼片段中,我們首先創(chuàng)建了一個(gè)名為hello的變量,并為其分配了字符串值。  接下來,我們通過分配之前的變量hello創(chuàng)建了另一個(gè)名為world的變量。  當(dāng)我們打印出他們的內(nèi)存地址時(shí),我們發(fā)現(xiàn)hello和world都具有相同的內(nèi)存地址,這表明它們是內(nèi)存中的同一對(duì)象。

>>> hello = 'Hello World!' >>> print(f'{hello} from: {id(hello)}') Hello World! from: 4341735856 >>> world = hello >>> print(f'{world} from: {id(world)}') Hello World! from: 4341735856 >>> >>> bored = {'a': 0, 'b': 1} >>> print(f'{bored} from: {id(bored)}') {'a': 0, 'b': 1} from: 4341577200 >>> more_bored = bored >>> print(f'{more_bored} from: {id(more_bored)}') {'a': 0, 'b': 1} from: 4341577200 >>> more_bored['c'] = 2 >>> bored {'a': 0, 'b': 1, 'c': 2} >>> more_bored {'a': 0, 'b': 1, 'c': 2}

在這種情況下,變量世界通常稱為變量hello的別名,通過分配現(xiàn)有變量來創(chuàng)建新變量的過程可以稱為別名。  在其他編程語言中,別名非常類似于與內(nèi)存中基礎(chǔ)對(duì)象有關(guān)的指針或引用。

在上面的代碼中,我們還可以看到,當(dāng)我們?yōu)樽值鋭?chuàng)建別名并修改別名的數(shù)據(jù)時(shí),該修改也將應(yīng)用于原始變量,因?yàn)樵诤笈_(tái),我們修改了內(nèi)存中的同一字典對(duì)象。

3. 比較運(yùn)算符:== vs. is

在各種情況下,我們需要比較兩個(gè)對(duì)象作為決策點(diǎn),以便在滿足或不滿足特定條件時(shí)應(yīng)用不同的功能。 就相等比較而言,我們可以使用兩個(gè)比較運(yùn)算符:==和is。  一些新的Python學(xué)習(xí)者可能會(huì)錯(cuò)誤地認(rèn)為它們是相同的,但是有細(xì)微差別。

考慮以下示例。 我們創(chuàng)建了兩個(gè)相同項(xiàng)目的列表。 當(dāng)我們使用==運(yùn)算符比較兩個(gè)列表時(shí),比較結(jié)果為True。  當(dāng)我們使用is運(yùn)算符比較兩個(gè)列表時(shí),比較結(jié)果為False。 他們?yōu)槭裁串a(chǎn)生不同的結(jié)果?  這是因?yàn)?=運(yùn)算符會(huì)比較值,而is運(yùn)算符會(huì)比較標(biāo)識(shí)(即內(nèi)存地址)。

正如您所期望的,這些變量引用了內(nèi)存中的同一對(duì)象,它們不僅具有相同的值,而且具有相同的標(biāo)識(shí)。  這導(dǎo)致==和is運(yùn)算符的評(píng)估結(jié)果相同,如下面涉及str0和str1的示例所示:

>>> list0 = [1, 2, 3, 4] >>> list1 = [1, 2, 3, 4] >>> print(f'list0 == list1: {list0 == list1}') list0 == list1: True >>> print(f'list0 is list1: {list0 is list1}') list0 is list1: False >>> print(f'list0 id: {id(list0)}') list0 id: 4341753408 >>> print(f'list1 id: {id(list1)}') list1 id: 4341884240 >>> >>> str0 = 'Hello' >>> str1 = str0 >>> print(f'str0 == str1: {str0 == str1}') str0 == str1: True >>> print(f'str0 is str1: {str0 is str1}') str0 is str1: True >>> print(f'str0 id: {id(str0)}') str0 id: 4341981808 >>> print(f'str1 id: {id(str1)}') str1 id: 4341981808

4. 整數(shù)緩存

我們?cè)诰幊讨薪?jīng)常使用的一組數(shù)據(jù)是整數(shù)。  在Python中,解釋器通常會(huì)緩存介于-5到256之間的小整數(shù)。這意味著在啟動(dòng)Python解釋器時(shí),這些整數(shù)將被創(chuàng)建并可供以后在內(nèi)存中使用。  以下代碼片段顯示了此功能:

>>> number_range = range(-10, 265) >>> id_counters = {x: 0 for x in number_range} >>> id_records = {x: 0 for x in number_range} >>>  >>> for _ in range(1000): ...     for number in number_range: ...         idid_number = id(number) ...         if id_records[number] != id_number: ...             id_records[number] = id_number ...             id_counters[number] += 1 ...  >>> [x for x in id_counters.keys() if id_counters[x] > 1] [-10, -9, -8, -7, -6, 257, 258, 259, 260, 261, 262, 263, 264]

在上面的代碼中,我創(chuàng)建了兩個(gè)字典,其中id_counters跟蹤每個(gè)整數(shù)的唯一標(biāo)識(shí)的計(jì)數(shù),而id_records跟蹤整數(shù)的最新標(biāo)識(shí)。  對(duì)于介于-10到265之間的整數(shù),如果新整數(shù)的標(biāo)識(shí)與現(xiàn)有整數(shù)不同,則相應(yīng)的計(jì)數(shù)器將遞增1。 我重復(fù)了這個(gè)過程1000次。

代碼的最后一行使用列表推導(dǎo)技術(shù)向您顯示具有多個(gè)同一性的整數(shù)。 顯然,經(jīng)過1000次后,從-5到256的整數(shù)對(duì)于每個(gè)整數(shù)僅具有一個(gè)標(biāo)識(shí),如上一段所述。  要了解有關(guān)Python列表理解的更多信息,您可以參考我以前關(guān)于此的文章:

5. 淺層和深層副本

有時(shí),我們需要制作現(xiàn)有對(duì)象的副本,以便我們可以更改一個(gè)副本而不更改另一個(gè)副本。  內(nèi)置的復(fù)制模塊為此提供了兩種方法:copy()和deepcopy(),它們分別進(jìn)行淺拷貝和深拷貝。  如果您不知道它們是什么,讓我們利用id()函數(shù)來了解這兩個(gè)概念。

>>> import copy >>> original = [[0, 1], 2, 3] >>> print(f'{original} id: {id(original)}, embeded list id: {id(original[0])}') [[0, 1], 2, 3] id: 4342107584, embeded list id: 4342106784 >>> copycopy0 = copy.copy(original) >>> print(f'{copy0} id: {id(copy0)}, embeded list id: {id(copy0[0])}') [[0, 1], 2, 3] id: 4341939968, embeded list id: 4342106784 >>> copycopy1 = copy.deepcopy(original) >>> print(f'{copy1} id: {id(copy1)}, embeded list id: {id(copy1[0])}') [[0, 1], 2, 3] id: 4341948160, embeded list id: 4342107664

我們首先創(chuàng)建了一個(gè)名為original的列表變量,它由一個(gè)嵌套列表和兩個(gè)整數(shù)組成。  然后,我們分別使用copy()和deepcopy()方法制作了兩個(gè)副本(copy0和copy1)。  如我們所料,原始的copy0和copy1具有相同的值(即[[0,1],2,3])。  但是,它們具有不同的身份,因?yàn)榕c別名不同,copy()和deepcopy()方法均會(huì)在內(nèi)存中創(chuàng)建新對(duì)象,從而使新副本具有不同的身份。

淺層副本和深層副本之間最本質(zhì)的區(qū)別是,深層復(fù)制將為原始復(fù)合對(duì)象遞歸創(chuàng)建副本,而淺層復(fù)制將在適用的情況下保留對(duì)現(xiàn)有對(duì)象的引用。  在上面顯示的示例中,變量original實(shí)際上是一個(gè)復(fù)合對(duì)象(即一個(gè)列表嵌套在另一個(gè)列表中)。

在這種情況下,使用copy()方法,變量copy0的第一個(gè)元素與原始的第一個(gè)元素具有相同的標(biāo)識(shí)(即,相同的對(duì)象)。  相比之下,deepcopy()方法在內(nèi)存中復(fù)制嵌套列表,以使copy1中的第一個(gè)元素具有與原始元素不同的標(biāo)識(shí)。

但是在深度復(fù)制中"遞歸"是什么意思?  這意味著如果存在多層嵌套(例如,嵌套在列表中的列表,又嵌套在另一個(gè)列表中),則deepcopy()方法將為每一層創(chuàng)建新對(duì)象。  請(qǐng)參見以下示例以了解此功能:

>>> mul_nested = [[[0, 1], 2], 3] >>> print(f'{mul_nested} id: {id(mul_nested)}, inner id: {id(mul_nested[0])}, innermost id: {id(mul_nested[0][0])}') [[[0, 1], 2], 3] id: 4342107824, inner id: 4342106944, innermost id: 4342107424 >>> mul_nested_dc = copy.deepcopy(mul_nested) >>> print(f'{mul_nested_dc} id: {id(mul_nested_dc)}, inner id: {id(mul_nested_dc[0])}, innermost id: {id(mul_nested_dc[0][0])}') [[[0, 1], 2], 3] id: 4342107264, inner id: 4342107984, innermost id: 4342107904

6. 數(shù)據(jù)可變性

Python編程中的一個(gè)高級(jí)主題與數(shù)據(jù)可變性有關(guān)。 一般來說,不可變數(shù)據(jù)是指其值在創(chuàng)建后便無法更改的對(duì)象,例如整數(shù),字符串和元組。  相比之下,可變數(shù)據(jù)是指其值在創(chuàng)建后可以更改的那些對(duì)象,例如列表,字典和集合。

需要注意的一件事是,通過"更改值",我們的意思是是否可以更改內(nèi)存中的基礎(chǔ)對(duì)象。 在我的上一篇文章中可以找到關(guān)于數(shù)據(jù)可變性的詳盡討論:

不可變與可變

為了本文討論id()函數(shù)的目的,讓我們考慮以下示例。  對(duì)于不可變數(shù)據(jù)類型(代碼片段中的整數(shù)變量千),當(dāng)我們嘗試更改其值時(shí),會(huì)在內(nèi)存中創(chuàng)建一個(gè)新的整數(shù),這由千變量的新標(biāo)識(shí)所反映。  換句話說,原始的基礎(chǔ)整數(shù)對(duì)象無法更改。 嘗試更改整數(shù)只會(huì)在內(nèi)存中創(chuàng)建一個(gè)新對(duì)象。

>>> thousand = 1000 >>> print(f'{thousand} id: {id(thousand)}') 1000 id: 4342004944 >>> thousand += 1 >>> print(f'{thousand} id: {id(thousand)}') 1001 id: 4342004912 >>> numbers = [4, 3, 2] >>> print(f'{numbers} id: {id(numbers)}') [4, 3, 2] id: 4342124624 >>> numbers += [1] >>> print(f'{numbers} id: {id(numbers)}') [4, 3, 2, 1] id: 4342124624

如果這讓您感到困惑,讓我們看看可變數(shù)據(jù)類型發(fā)生了什么&mdash;在我們的例子中是列表變量編號(hào)。  如上面的代碼所示,當(dāng)我們嘗試更改數(shù)字的值時(shí),變量號(hào)得到了更新,并且更新后的列表仍具有相同的標(biāo)識(shí),從而確認(rèn)了列表類型的對(duì)象的可變性。

上述就是小編為大家分享的使用id()理解Python中的6個(gè)關(guān)鍵概念分別是怎樣的了,如果剛好有類似的疑惑,不妨參照上述分析進(jìn)行理解。如果想知道更多相關(guān)知識(shí),歡迎關(guān)注億速云行業(yè)資訊頻道。

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI