Untuk apa fungsi id () digunakan?

99

Saya membaca dokumen Python 2 dan memperhatikan id()fungsinya:

Kembalikan "identitas" dari suatu objek. Ini adalah bilangan bulat (atau bilangan bulat panjang) yang dijamin unik dan konstan untuk objek ini selama masa pakainya. Dua objek dengan masa pakai yang tidak tumpang tindih mungkin memiliki nilai id () yang sama.

Detail implementasi CPython: Ini adalah alamat objek di memori.

Jadi, saya bereksperimen dengan menggunakan id()daftar:

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

Apa bilangan bulat yang dikembalikan dari fungsi? Apakah ini identik dengan alamat memori di C? Jika ya, mengapa integer tidak sesuai dengan ukuran tipe data?

Kapan id()digunakan dalam praktik?

Thanakron Tandavas
sumber
4
Hanya karena Anda menyimpan (katakanlah) int 32 bit dalam struktur data dalam bahasa skrip tidak berarti Anda akan menggunakan lebih banyak memori 32 bit. SELALU ada metadata yang dilampirkan ke data APA PUN yang Anda simpan. jenis, ukuran, panjang, bla bla bla.
Marc B
cpython mengalokasikan dari heap yang diacak saat objek di malloc dan gratis.
tdelaney
Nomor Python bukanlah data yang sederhana. Mereka adalah objek yang menggunakan long secara internal untuk memulai, lalu dipromosikan secara otomatis ke representasi gaya BigNumber jika nilainya menjadi terlalu besar.
Gareth Latty

Jawaban:

156

Posting Anda menanyakan beberapa pertanyaan:

Berapa angka yang dikembalikan dari fungsi tersebut?

Ini adalah " integer (atau integer panjang) yang dijamin unik dan konstan untuk objek ini selama masa pakainya. " (Python Standard Library - Built-in Functions) Sebuah nomor unik. Tidak lebih dan tidak kurang. Anggap saja sebagai nomor jaminan sosial atau nomor id karyawan untuk objek Python.

Apakah sama dengan alamat memori di C?

Secara konseptual, ya, karena keduanya dijamin unik di alam semesta mereka selama hidup mereka. Dan dalam satu implementasi Python, sebenarnya itu adalah alamat memori dari objek C.

Jika ya, mengapa jumlahnya tidak bertambah secara instan dengan ukuran tipe data (saya berasumsi bahwa itu akan menjadi int)?

Karena list bukan array, dan elemen list adalah referensi, bukan objek.

Kapan kita benar-benar menggunakan id( )fungsi?

Hampir tidak pernah. id()(atau yang setara) digunakan di isoperator.

Robᵩ
sumber
Kami menggunakan id () biasanya untuk tujuan demonstrasi seperti di sini stackoverflow.com/questions/17246693/…
Nabin
49

Itulah identitas lokasi objek di memori ...

Contoh ini mungkin dapat membantu Anda memahami konsepnya lebih dalam.

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

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

> 1532352
> 1532352
> 1532352
> 1532352

Ini semua menunjuk ke lokasi yang sama di memori, itulah sebabnya nilainya sama. Dalam contoh, 1hanya disimpan sekali, dan hal lain yang menunjuk 1akan merujuk ke lokasi memori tersebut.

brbcoding
sumber
9
Tetapi jika Anda menggunakan angka di luar kisaran -5 hingga 256, Anda tidak akan mendapatkan id yang sama untuk variabel fii.
saurav
itu sangat menarik. Bisakah Anda berbagi lebih banyak?
jouell
3
Saya pikir jawaban ini menyesatkan karena ini tidak berlaku untuk kebanyakan angka; lihat "adalah" operator berperilaku tidak terduga dengan bilangan bulat .
kevinji
8

id()mengembalikan alamat objek yang direferensikan (dalam CPython), tetapi kebingungan Anda berasal dari fakta bahwa daftar python sangat berbeda dari array C. Dalam daftar python, setiap elemen adalah referensi . Jadi apa yang Anda lakukan jauh lebih mirip dengan kode C ini:

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]);

Dengan kata lain, Anda mencetak alamat dari referensi dan bukan alamat relatif ke tempat daftar Anda disimpan.

Dalam kasus saya, saya telah menemukan id()fungsi yang berguna untuk membuat gagang buram untuk kembali ke kode C saat memanggil pythondari C. Dengan melakukan itu, Anda dapat dengan mudah menggunakan kamus untuk mencari objek dari pegangannya dan dijamin unik.

Kesalahan fatal
sumber
7

Jawaban Rob (paling banyak dipilih di atas) benar. Saya ingin menambahkan bahwa dalam beberapa situasi menggunakan ID berguna karena memungkinkan untuk perbandingan objek dan menemukan objek mana yang merujuk ke objek Anda.

Nanti biasanya membantu Anda misalnya untuk men-debug bug aneh di mana objek yang bisa berubah diteruskan sebagai parameter untuk mengatakan kelas dan ditugaskan ke vars lokal di kelas. Mutasi objek tersebut akan mengubah vars di kelas. Ini memanifestasikan dirinya dalam perilaku aneh di mana banyak hal berubah pada saat bersamaan.

Baru-baru ini saya mengalami masalah ini dengan aplikasi Python / Tkinter di mana pengeditan teks dalam satu bidang entri teks mengubah teks di bidang lain saat saya mengetik :)

Berikut adalah contoh bagaimana Anda dapat menggunakan function id () untuk melacak di mana referensi tersebut berada. Dengan segala cara ini bukanlah solusi yang mencakup semua kasus yang mungkin, tetapi Anda mengerti. Sekali lagi ID digunakan di latar belakang dan pengguna tidak melihatnya:

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()) )

KELUARAN:

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'}

Garis bawah pada nama variabel digunakan untuk mencegah perselisihan nama. Fungsi menggunakan argumen "dari mana" sehingga Anda dapat memberi tahu mereka di mana harus mulai mencari referensi. Argumen ini diisi oleh fungsi yang mencantumkan semua nama dalam namespace tertentu. Globals () adalah salah satu fungsinya.

Arijan
sumber
Penjelasan yang bagus!
Neeraj Verma
5

Saya memulai dengan python dan saya menggunakan id ketika saya menggunakan shell interaktif untuk melihat apakah variabel saya ditugaskan ke hal yang sama atau apakah mereka terlihat sama.

Setiap nilai adalah sebuah id, yang merupakan nomor unik yang terkait dengan tempatnya disimpan di memori komputer.

lontgomjr
sumber
5

Jika Anda menggunakan python 3.4.1 maka Anda mendapatkan jawaban yang berbeda untuk pertanyaan Anda.

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

kembali:

1705950792   
1705950808  # increased by 16   
1705950824  # increased by 16

Bilangan bulat -5untuk 256memiliki id konstan, dan jika menemukannya berkali-kali, id-nya tidak berubah, tidak seperti semua angka lain sebelum atau sesudahnya yang memiliki id berbeda setiap kali Anda menemukannya. Angka dari -5agar 256memiliki id dalam urutan yang meningkat dan berbeda menurut 16.

Nomor yang dikembalikan oleh id()fungsi adalah id unik yang diberikan untuk setiap item yang disimpan dalam memori dan secara analogi sama dengan lokasi memori di C.

Dhvanan Shah
sumber
2

Jawabannya tidak pernah. ID terutama digunakan secara internal untuk Python.

Rata-rata programmer Python mungkin tidak perlu menggunakan id()kode mereka.

Gareth Latty
sumber
3
Mungkin saya tidak biasa-biasa saja, tapi saya menggunakan id()cukup banyak. Dua kasus penggunaan di luar kepala saya: A (hand-rolled, ad-hoc) identity dict dan custom repr()untuk objek yang identitasnya penting, tetapi defaultnya reprtidak sesuai.
5
@ Delnan Saya tidak akan membantah itu adalah kasus umum.
Gareth Latty
2

The isOperator menggunakannya untuk memeriksa apakah dua benda yang identik (sebagai lawan yang sama). Nilai sebenarnya yang dikembalikan dari id()hampir tidak pernah digunakan untuk apa pun karena tidak benar-benar memiliki arti, dan bergantung pada platform.

omz
sumber
2

Ini adalah alamat objek di memori, persis seperti yang dikatakan dokter. Namun, itu memiliki metadata yang menyertainya, properti objek dan lokasi dalam memori diperlukan untuk menyimpan metadata. Jadi, saat Anda membuat variabel yang disebut list, Anda juga membuat metadata untuk daftar dan elemennya.

Jadi, kecuali Anda seorang guru absolut dalam bahasa tersebut, Anda tidak dapat menentukan id elemen berikutnya dari daftar Anda berdasarkan elemen sebelumnya, karena Anda tidak tahu apa yang dialokasikan bahasa bersama dengan elemennya.

Lajos Arpad
sumber
1
Sebenarnya, menjadi guru Python tidak akan banyak gunanya memprediksi objek apa pun id(). Anda harus sangat akrab dengan pengelola memori (jamak!) Yang bersangkutan, mengetahui status pastinya di beberapa titik waktu, dan mengetahui urutan persisnya di mana objek telah dialokasikan. Dengan kata lain: Tidak akan terjadi.
Anda adalah guru Python mutlak jika Anda benar-benar tahu semua nuansanya, termasuk kemungkinan pengelola memori.
Lajos Arpad
1
Mengetahui Python dan mengetahui implementasi tertentu (misalnya CPython) adalah dua hal yang sangat berbeda. Dan bahkan mengetahui CPython di dalam tidak akan membantu, karena ada beberapa manajer memori yang dipanggil CPython yang bukan bagian dari CPython tetapi bagian dari sistem operasi masing-masing. Dan seperti yang saya katakan sebelumnya, bahkan mengetahui semua hal non-Python ini tidak akan membantu Anda, karena alamat sebenarnya bergantung pada status run-time pengelola memori, dan terkadang bahkan diacak.
1
Belum lagi, akan percuma untuk mengetahuinya, karena mengandalkan hal seperti itu akan mengandalkan detail implementasi dan karenanya menjadi rapuh dan tidak fleksibel.
Gareth Latty
2

Saya punya ide untuk menggunakan nilai id()dalam logging.
Ini murah untuk didapat dan itu cukup pendek.
Dalam kasus saya, saya menggunakan tornado dan id()ingin memiliki jangkar ke pesan grup yang tersebar dan dicampur melalui file dengan soket web.

Daneel S. Yaitskov
sumber
0

Pada python 3 id ditugaskan ke nilai bukan variabel. Artinya, jika Anda membuat dua fungsi seperti di bawah ini, ketiga id tersebut sama.

>>> def xyz():
...     q=123
...     print(id(q))
...
>>> def iop():
...     w=123
...     print(id(w))
>>> xyz()
1650376736
>>> iop()
1650376736
>>> id(123)
1650376736
Asish Kumar
sumber
Meskipun ini bertentangan dengan penjelasan sebelumnya, hal itu tampaknya terjadi dan saya tidak tahu mengapa. Ada penjelasan? Misalnya x [0] = "abc" x [1] = "def" q = ["abc", "def"]. Id (x) == Id (q) adalah True. Kebetulan?
VMMF
0

Saya agak terlambat dan saya akan berbicara tentang Python3. Untuk memahami apa itu id () dan bagaimana itu (dan Python) bekerja, pertimbangkan contoh berikut:

>>> 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

Anda perlu memikirkan semua yang ada di sisi kanan sebagai objek. Setiap kali Anda membuat tugas - Anda membuat objek baru dan itu berarti id baru. Di tengah Anda bisa melihat objek "liar" yang dibuat hanya untuk fungsi - id (1000). Jadi, seumur hidup itu hanya untuk baris kode itu. Jika Anda memeriksa baris berikutnya - Anda melihat bahwa ketika kita membuat variabel baru x, itu memiliki id yang sama dengan objek liar itu. Cukup banyak berfungsi seperti alamat memori.

Tomas
sumber
0

Hati-hati (tentang jawaban di bawah) ... Itu hanya benar karena 123 berada di antara -5 dan 256 ...

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
Wah
sumber