İd () işlevi ne için kullanılır?


99

Python 2 belgelerini okudum ve id()işlevi fark ettim :

Bir nesnenin "kimliğini" döndürür. Bu, ömrü boyunca bu nesne için benzersiz ve sabit olması garanti edilen bir tam sayıdır (veya uzun tam sayıdır). Örtüşmeyen yaşam sürelerine sahip iki nesne aynı id () değerine sahip olabilir.

CPython uygulama ayrıntısı: Bu, bellekteki nesnenin adresidir.

Bu yüzden id()bir liste kullanarak deney yaptım :

>>> list = [1,2,3]
>>> id(list[0])
31186196
>>> id(list[1])
31907092 // increased by 896
>>> id(list[2])
31907080 // decreased by 12

İşlevden döndürülen tamsayı nedir? C'deki bellek adresleriyle eş anlamlı mı? Öyleyse, neden tam sayı veri türünün boyutuna karşılık gelmiyor?

id()Pratikte ne zaman kullanılır?


4
Bir komut dosyası dilinde bir veri yapısında 32 bit int depolamanız (diyelim), 32 bit daha fazla bellek kullanacağınız anlamına gelmez. depoladığınız HER veriye HER ZAMAN eklenmiş meta veri vardır. tür, boyut, uzunluk, blah blah blah.
Marc B

cpython, nesneler malloc'd ve serbest bırakıldıkça karıştırılan bir yığından ayırır.
tdelaney

Python sayıları basit veri parçaları değildir. Başlamak için dahili olarak uzun kullanan nesnelerdir, ardından değer çok büyük olursa BigNumber tarzı bir temsile otomatik olarak yükselir.
Gareth Latty

1
Muhtemelen yararlı: Python'unuzu Büyük

Yanıtlar:


156

Gönderiniz birkaç soru soruyor:

İşlevden döndürülen sayı nedir?

Bu " Yaşam süresi boyunca bu nesne için benzersiz ve sabit olması garanti edilen bir tamsayıdır (veya uzun tam sayıdır). " (Python Standart Kitaplığı - Yerleşik İşlevler) Benzersiz bir sayı. Ne daha fazlası ne de daha azı. Python nesneleri için bir sosyal güvenlik numarası veya çalışan kimlik numarası olarak düşünün.

C'deki bellek adresleriyle aynı mı?

Kavramsal olarak, evet, her ikisinin de yaşamları boyunca kendi evrenlerinde benzersiz olmaları garantilidir. Ve belirli bir Python uygulamasında, aslında karşılık gelen C nesnesinin bellek adresidir.

Evetse, neden veri türünün boyutuna göre sayı anında artmıyor (int olacağını varsayıyorum)?

Bir liste bir dizi olmadığından ve liste öğesi bir nesne değil, bir referanstır.

Gerçekten ne zaman kullanıyoruz id( )Fonksiyonu ?

Neredeyse hiç. id()(veya eşdeğeri) isoperatörde kullanılır .


İd () 'yi genellikle burada stackoverflow.com/questions/17246693/…
Nabin

49

Bu konumun kimliğiHafızadaki nesnenin ...

Bu örnek, kavramı biraz daha anlamanıza yardımcı olabilir.

foo = 1
bar = foo
baz = bar
fii = 1

print id(foo)
print id(bar)
print id(baz)
print id(fii)

> 1532352
> 1532352
> 1532352
> 1532352

Bunların hepsi bellekte aynı yere işaret ediyor, bu yüzden değerleri aynı. Örnekte, 1yalnızca bir kez saklanır ve işaret eden her şey 1bu bellek konumuna başvurur.


9
Ancak -5 ile 256 aralığının dışındaki sayıları kullanırsanız, fii değişkeni için aynı kimliği alamazsınız.
saurav

bu son derece ilginç. Daha fazlasını paylaşabilir misin?
jouell

3
Bu cevabın yanıltıcı olduğunu düşünüyorum çünkü bu çoğu sayı için geçerli değildir; bkz. "eşittir" operatörü beklenmedik şekilde tamsayılarla davranır .
kevinji

8

id()referans verilen nesnenin adresini döndürür (CPython'da), ancak kafa karışıklığınız python listelerinin C dizilerinden çok farklı olmasından kaynaklanıyor. Bir python listesinde her öğe bir referanstır . Yani yaptığınız şey bu C koduna çok daha benzer:

int *arr[3];
arr[0] = malloc(sizeof(int));
*arr[0] = 1;
arr[1] = malloc(sizeof(int));
*arr[1] = 2;
arr[2] = malloc(sizeof(int));
*arr[2] = 3;
printf("%p %p %p", arr[0], arr[1], arr[2]);

Başka bir deyişle, adresi listenizin depolandığı yere göre değil referanstan yazdırıyorsunuz .

Benim durumumda, id()C'den çağırırken C koduna dönmek için opak tutamaçlar oluşturmak için kullanışlı bir işlev buldum python. Bunu yaparak, nesneyi kendi tanıtıcısından aramak için kolayca bir sözlük kullanabilirsiniz ve benzersiz olması garanti edilir.


7

Rob'un cevabı (en çok yukarıda oylanan) doğru. Nesnelerin karşılaştırılmasına ve hangi nesnelerin sizin nesnelerinize atıfta bulunduğunu bulmaya izin verdiği için bazı durumlarda kimlik kullanmanın yararlı olduğunu eklemek isterim.

Daha sonra genellikle, örneğin sınıfları söylemek için değişken nesnelerin parametre olarak iletildiği ve bir sınıftaki yerel değişkenlere atandığı garip hataların hatalarını ayıklamanıza yardımcı olur. Bu nesneleri değiştirmek, bir sınıftaki değişkenleri değiştirecektir. Bu, birden fazla şeyin aynı anda değiştiği garip davranışta kendini gösterir.

Son zamanlarda, bir metin giriş alanındaki metni düzenlemenin, yazdığım sırada metni değiştirdiği bir Python / Tkinter uygulamasında bu sorunu yaşadım :)

İşte bu referansların nerede olduğunu izlemek için id () işlevini nasıl kullanabileceğinize dair bir örnek. Elbette bu, tüm olası durumları kapsayan bir çözüm değil, ancak fikri anladınız. Yine kimlikler arka planda kullanılır ve kullanıcı bunları görmez:

class democlass:
    classvar = 24

    def __init__(self, var):
        self.instancevar1 = var
        self.instancevar2 = 42

    def whoreferencesmylocalvars(self, fromwhere):
        return {__l__: {__g__
                    for __g__ in fromwhere
                        if not callable(__g__) and id(eval(__g__)) == id(getattr(self,__l__))
                    }
                for __l__ in dir(self)
                    if not callable(getattr(self, __l__)) and __l__[-1] != '_'
                }

    def whoreferencesthisclassinstance(self, fromwhere):
        return {__g__
                    for __g__ in fromwhere
                        if not callable(__g__) and id(eval(__g__)) == id(self)
                }

a = [1,2,3,4]
b = a
c = b
democlassinstance = democlass(a)
d = democlassinstance
e = d
f = democlassinstance.classvar
g = democlassinstance.instancevar2

print( 'My class instance is of', type(democlassinstance), 'type.')
print( 'My instance vars are referenced by:', democlassinstance.whoreferencesmylocalvars(globals()) )
print( 'My class instance is referenced by:', democlassinstance.whoreferencesthisclassinstance(globals()) )

ÇIKTI:

My class instance is of <class '__main__.democlass'> type.
My instance vars are referenced by: {'instancevar2': {'g'}, 'classvar': {'f'}, 'instancevar1': {'a', 'c', 'b'}}
My class instance is referenced by: {'e', 'd', 'democlassinstance'}

Değişken adlarındaki alt çizgiler, ad çakışmalarını önlemek için kullanılır. İşlevler "nereden" argümanını kullanır, böylece onlara referans aramaya nereden başlayacaklarını bildirebilirsiniz. Bu bağımsız değişken, belirli bir ad alanındaki tüm adları listeleyen bir işlev tarafından doldurulur. Globals () böyle bir işlevdir.


Harika açıklama!
Neeraj Verma

5

Python ile başlıyorum ve değişkenlerimin aynı şeye atanıp atanmadığını veya sadece aynı görünüp görünmediğini görmek için etkileşimli kabuğu kullandığımda id kullanıyorum.

Her değer, bilgisayarın belleğinde depolandığı yerle ilgili benzersiz bir sayı olan bir kimliktir.


5

Python 3.4.1 kullanıyorsanız, sorunuza farklı bir yanıt alırsınız.

list = [1,2,3]
id(list[0])
id(list[1])
id(list[2])

İadeler:

1705950792   
1705950808  # increased by 16   
1705950824  # increased by 16

Tamsayılar -5için 256sürekli bir kimliğe sahip ve önce veya sonra bunu diğer bütün sayılar aksine onun kimliği değişmez birden çok kez, bulma ile ilgili farklı kimliğe sahip bunu bulmak her zaman. Gelen sayılar-5 için 256artan sırayla kimliklerini ve farklılık 16.

id()İşlev tarafından döndürülen sayı , bellekte depolanan her öğeye verilen benzersiz bir kimliktir ve C'deki bellek konumu ile benzer şekilde aynıdır.


2

Cevap hemen hemen asla. Kimlikler çoğunlukla dahili olarak Python'da kullanılır.

Ortalama bir Python programcısının id()kodlarında muhtemelen hiçbir zaman kullanması gerekmeyecektir .


3
Belki de ortalama değilim, ama id()biraz kullanıyorum. Aklıma gelen iki kullanım durumu: Bir (elle haddelenmiş, geçici) kimlik diktesi ve repr()kimliğin önemli olduğu ancak varsayılanın repruygun olmadığı bir nesne için bir gelenek .

5
@delnan Bunların yaygın durumlar olduğunu iddia etmem.
Gareth Latty

2

isOperatör (eşit aksine) iki nesne aynı olup olmadığını kontrol etmek için kullanır. Geri dönen gerçek değer id()hemen hemen hiçbir şey için kullanılmaz çünkü gerçekten bir anlamı yoktur ve platforma bağlıdır.


2

Tam da dokümanın dediği gibi bellekteki nesnenin adresidir. Bununla birlikte, kendisine eklenmiş meta veriler vardır, meta verileri depolamak için nesnenin özellikleri ve bellekteki konum gereklidir. Dolayısıyla, list adlı değişkeninizi oluşturduğunuzda, liste ve öğeleri için de meta veriler oluşturursunuz.

Dolayısıyla, dilde mutlak bir uzman değilseniz, listenizin bir sonraki öğesinin kimliğini önceki öğeye göre belirleyemezsiniz, çünkü dilin öğelerle birlikte neyi ayırdığını bilmiyorsunuz.


1
Aslında, bir Python gurusu olmak herhangi bir nesneyi tahmin etmekte pek işe yaramayacaktır id(). Söz konusu bellek yöneticilerine (çoğul!) Yakından aşina olmanız, zamanın bir noktasında tam durumlarını bilmeniz ve nesnelerin hangi sırayla tahsis edildiğini tam olarak bilmeniz gerekir. Başka bir deyişle: Olmayacak.

Olası bellek yöneticileri de dahil olmak üzere tüm nüanslarını kesinlikle biliyorsanız, mutlak bir Python gurusunuz.
Lajos Arpad

1
Python'u bilmek ve belirli bir uygulamayı (örneğin CPython) bilmek tamamen farklı iki şeydir. Ve CPython'u içten dışa bilmek bile yardımcı olmaz, çünkü CPython'un çağırdığı birkaç bellek yöneticisi vardır, bunlar CPython'un bir parçası değil, ilgili işletim sisteminin bir parçasıdır. Ve daha önce de söylediğim gibi, tüm bu Python dışı şeylerin bilinmesi bile size yardımcı olmayacaktır, çünkü gerçek adresler bellek yöneticilerinin çalışma zamanı durumuna bağlıdır ve hatta bazen rastgele hale getirilmiştir.

1
Bahsetmiyorum bile, böyle bir şeye güvenmek bir uygulama ayrıntısına güvenmek ve dolayısıyla kırılgan ve esnek olmayacağından, bilmenin faydası olmaz.
Gareth Latty

2

id()Günlüğe kaydetmede değerini kullanmak için bir fikrim var .
Alması ucuz ve oldukça kısa.
Benim durumumda kasırga kullanıyorum ve id()web soketine göre dosyaya dağılmış ve karıştırılmış mesajları gruplandırmak için bir çapa olmasını istiyorum.


0

Python 3 itibariyle id bir değişkene değil bir değere atanır. Bu, aşağıdaki gibi iki işlev oluşturursanız, üç kimliğin de aynı olacağı anlamına gelir.

>>> def xyz():
...     q=123
...     print(id(q))
...
>>> def iop():
...     w=123
...     print(id(w))
>>> xyz()
1650376736
>>> iop()
1650376736
>>> id(123)
1650376736

Bu, önceki açıklamalarla çelişse de gerçekleşmiş gibi görünüyor ve nedenini bilmiyorum. Herhangi bir açıklama var mı? Örneğin x [0] = "abc" x [1] = "def" q = ["abc", "def"]. Id (x) == Id (q) Doğru. Tesadüf?
VMMF

0

Biraz geciktim ve Python3 hakkında konuşacağım. İd () nedir ve nasıl çalıştığını (ve Python) anlamak için sonraki örneği düşünün:

>>> x=1000
>>> y=1000
>>> id(x)==id(y)
False
>>> id(x)
4312240944
>>> id(y)
4312240912
>>> id(1000)
4312241104
>>> x=1000
>>> id(x)
4312241104
>>> y=1000
>>> id(y)
4312241200

Sağ taraftaki her şeyi nesneler olarak düşünmeniz gerekir. Her atama yaptığınızda - yeni nesne oluşturursunuz ve bu yeni kimlik anlamına gelir. Ortada sadece function - id (1000) için oluşturulmuş bir "wild" nesnesi görebilirsiniz. Öyleyse, yaşam süresi yalnızca bu kod satırı içindir. Bir sonraki satırı kontrol ederseniz - yeni x değişkenini oluşturduğumuzda, bu vahşi nesneyle aynı kimliğe sahip olduğunu görürsünüz. Hemen hemen hafıza adresi gibi çalışır.


0

Dikkatli olun (hemen aşağıdaki cevapla ilgili olarak) ... Bu sadece doğrudur çünkü 123, -5 ile 256 arasındadır ...

In [111]: q = 257                                                         

In [112]: id(q)                                                            
Out[112]: 140020248465168

In [113]: w = 257                                                         

In [114]: id(w)                                                           
Out[114]: 140020274622544

In [115]: id(257)                                                         
Out[115]: 140020274622768
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.