欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Python中的is和id用法分析

 更新時間:2015年01月26日 11:51:22   投稿:shichen2014  
這篇文章主要介紹了Python中的is和id用法,實例分析了is和id的功能及使用技巧,具有一定參考借鑒價值,需要的朋友可以參考下

本文實例講述了Python中的is和id用法。分享給大家供大家參考。具體分析如下:

(ob1 is ob2) 等價于 (id(ob1) == id(ob2))

首先id函數(shù)可以獲得對象的內(nèi)存地址,如果兩個對象的內(nèi)存地址是一樣的,那么這兩個對象肯定是一個對象。和is是等價的。Python源代碼為證。

復(fù)制代碼 代碼如下:
static PyObject *
 cmp_outcome(int op, register PyObject *v, register PyObject *w)
{
 int res = 0;
 switch (op) {
 case PyCmp_IS:
  res = (v == w);
 break;
 case PyCmp_IS_NOT:
res = (v != w);
 break;

但是請看下邊代碼的這種情況怎么會出現(xiàn)呢?

復(fù)制代碼 代碼如下:
In [1]: def bar(self, x):
...:     return self.x + y
...:
 
In [2]: class Foo(object):
...:     x = 9
...:     def __init__(self ,x):
...:         self.x = x
...:     bar = bar
...:    
 
In [3]: foo = Foo(5)
 
In [4]: foo.bar is Foo.bar
Out[4]: False
 
In [5]: id(foo.bar) == id(Foo.bar)
Out[5]: True

兩個對象用is判斷是False,用id判斷卻是True,這與我們已知的事實不符啊,這種現(xiàn)象該如何解釋呢?遇到這種情況最好的解決方法就是調(diào)用dis模塊去看下兩個比較語句到底做了什么。

復(fù)制代碼 代碼如下:
In [7]: dis.dis("id(foo.bar) == id(Foo.bar)")
          0 BUILD_MAP       10340
          3 BUILD_TUPLE     28527
          6 <46>          
          7 DELETE_GLOBAL   29281 (29281)
         10 STORE_SLICE+1
         11 SLICE+2      
         12 DELETE_SUBSCR 
         13 DELETE_SUBSCR 
         14 SLICE+2      
         15 BUILD_MAP       10340
         18 PRINT_EXPR    
         19 JUMP_IF_FALSE_OR_POP 11887
         22 DELETE_GLOBAL   29281 (29281)
         25 STORE_SLICE+1
 
In [8]: dis.dis("foo.bar is Foo.bar")
          0 BUILD_TUPLE     28527
          3 <46>          
          4 DELETE_GLOBAL   29281 (29281)
          7 SLICE+2      
          8 BUILD_MAP        8307
         11 PRINT_EXPR    
         12 JUMP_IF_FALSE_OR_POP 11887
         15 DELETE_GLOBAL   29281 (29281)

真實情況是當執(zhí)行.操作符的時候,實際是生成了一個proxy對象,foo.bar is Foo.bar的時候,兩個對象順序生成,放在棧里相比較,由于地址不同肯定是False,但是id(foo.bar) == id(Foo.bar)的時候就不同了,首先生成foo.bar,然后計算foo.bar的地址,計算完之后foo.bar的地址之后,就沒有任何對象指向foo.bar了,所以foo.bar對象就會被釋放。然后生成Foo.bar對象,由于foo.bar和Foo.bar所占用的內(nèi)存大小是一樣的,所以又恰好重用了原先foo.bar的內(nèi)存地址,所以id(foo.bar) == id(Foo.bar)的結(jié)果是True。

下面內(nèi)容由郵件Leo Jay大牛提供,他解釋的更加通透。

用id(expression a) == id(expression b)來判斷兩個表達式的結(jié)果是不是同一個對象的想法是有問題的。

foo.bar 這種形式叫 attribute reference [1],它是表達式的一種。foo是一個instance object,bar是一個方法,這個時候表達式foo.bar返回的結(jié)果叫method object。根據(jù)文檔:

When an instance attribute is referenced that isn't a data attribute,
its class is searched. If the name denotes a valid class attribute
that is a function object, a method object is created by packing
(pointers to) the instance object and the function object just found
together in an abstract object: this is the method object.

foo.bar本身并不是簡單的名字,而是表達式的計算結(jié)果,是一個 method object,在id(foo.bar)這樣的表達式里,method object只是一個臨時的中間變量而已,對臨時的中間變量做id是沒有意義的。

一個更明顯的例子是,

復(fù)制代碼 代碼如下:
print id(foo.bar) == id(foo.__init__)

輸出的結(jié)果也是True

看 id 的文檔:

Return the “identity” of an object. This is an integer (or long
integer) which is guaranteed to be unique and constant for this object
during its lifetime. Two objects with non-overlapping lifetimes may
have the same id() value.
CPython implementation detail: This is the address of the object in memory.

只有你能保證對象不會被銷毀的前提下,你才能用 id 來比較兩個對象。所以,如果你非要比的話,得這樣寫:

復(fù)制代碼 代碼如下:
fb = foo.bar
Fb = Foo.bar
print id(fb) == id(Fb)

即把兩個表達式的結(jié)果綁定到名字上,再來比是不是同一個對象,你才能得到正確的結(jié)果。

is表達式也是一樣的,你現(xiàn)在得到了正確的結(jié)果,完全是因為 CPython 現(xiàn)在的實現(xiàn)細節(jié)決定的?,F(xiàn)在的is的實現(xiàn),是左右兩邊的對象都計算出來,然后再比較這兩個對象的地址是否一樣。萬一哪天改成了,先算左邊,保存地址,把左邊釋放掉,再算右邊,再比較的話,你的is的結(jié)果可能就錯了。官方文檔里也提到了這個問題 。我認為正確的方法也是像id那樣,先把左右兩邊都計算下來,并顯式綁定到各自的名字上,然后再用is判斷。

希望本文所述對大家的Python程序設(shè)計有所幫助。

相關(guān)文章

  • Python的Pandas時序數(shù)據(jù)詳解

    Python的Pandas時序數(shù)據(jù)詳解

    這篇文章主要為大家詳細介紹了Pandas時序數(shù)據(jù),文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助
    2022-03-03
  • Python實現(xiàn)簡易凱撒密碼的示例代碼

    Python實現(xiàn)簡易凱撒密碼的示例代碼

    密碼的使用最早可以追溯到古羅馬時期,《高盧戰(zhàn)記》有描述愷撒曾經(jīng)使用密碼來傳遞信息,即所謂的“愷撒密碼”。本文將利用Python實現(xiàn)簡易的凱撒密碼,感興趣的可以了解一下
    2022-09-09
  • Python獲取DLL和EXE文件版本號的方法

    Python獲取DLL和EXE文件版本號的方法

    這篇文章主要介紹了Python獲取DLL和EXE文件版本號的方法,實例分析了Python獲取系統(tǒng)文件信息的技巧,需要的朋友可以參考下
    2015-03-03
  • Python入門篇之對象類型

    Python入門篇之對象類型

    本章中我們將講述Python的對象類型,包括數(shù)字、整型、布爾型、長整形、浮點型、復(fù)數(shù)型、字符串、列表、元組、字典等。
    2014-10-10
  • 圖文詳解matlab原始處理圖像幾何變換

    圖文詳解matlab原始處理圖像幾何變換

    Matlab 擅長于操作矩陣,而圖像其實就是矩陣,這篇文章主要給大家介紹了關(guān)于matlab原始處理圖像幾何變換的相關(guān)資料,需要的朋友可以參考下
    2021-07-07
  • pyhton中__pycache__文件夾的產(chǎn)生與作用詳解

    pyhton中__pycache__文件夾的產(chǎn)生與作用詳解

    這篇文章主要介紹了pyhton中__pycache__文件夾的產(chǎn)生與作用詳解,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-11-11
  • 對python修改xml文件的節(jié)點值方法詳解

    對python修改xml文件的節(jié)點值方法詳解

    今天小編就為大家分享一篇對python修改xml文件的節(jié)點值方法詳解,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2018-12-12
  • Python Pickling 和 Unpickling 的區(qū)別

    Python Pickling 和 Unpickling 的區(qū)別

    Python中的Pickling和Unpickling是與數(shù)據(jù)序列化和反序列化相關(guān)的重要概念,本文主要介紹了Python Pickling和Unpickling的區(qū)別,具有一定的參考價值,感興趣的可以了解一下
    2023-11-11
  • 簡單了解python的內(nèi)存管理機制

    簡單了解python的內(nèi)存管理機制

    這篇文章主要介紹了簡單了解python的內(nèi)存管理機制,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2019-07-07
  • 小試Python中的pack()使用方法

    小試Python中的pack()使用方法

    這篇文章主要介紹了小試Python中的pack()使用方法,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-06-06

最新評論