id () ฟังก์ชั่นใช้สำหรับอะไร?


103

ฉันอ่านเอกสาร Python 2และสังเกตเห็นid()ฟังก์ชัน:

ส่งคืน "เอกลักษณ์" ของวัตถุ นี่คือจำนวนเต็ม (หรือจำนวนเต็มยาว) ซึ่งรับประกันว่าจะไม่ซ้ำกันและคงที่สำหรับวัตถุนี้ตลอดอายุการใช้งาน วัตถุสองชิ้นที่มีอายุขัยไม่ทับซ้อนกันอาจมีค่า id () เหมือนกัน

รายละเอียดการใช้งาน CPython: นี่คือที่อยู่ของวัตถุในหน่วยความจำ

ดังนั้นฉันจึงทดลองโดยใช้id()กับรายการ:

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

จำนวนเต็มที่ส่งกลับจากฟังก์ชันคืออะไร? ตรงกันกับที่อยู่หน่วยความจำใน C หรือไม่? ถ้าเป็นเช่นนั้นเหตุใดจำนวนเต็มจึงไม่ตรงกับขนาดของชนิดข้อมูล

เมื่อถูกid()นำมาใช้ในการปฏิบัติ?


4
เพียงเพราะคุณจัดเก็บ (พูด) int 32 บิตในโครงสร้างข้อมูลในภาษาสคริปต์ไม่ได้หมายความว่าคุณจะใช้หน่วยความจำเพิ่มขึ้น 32 บิต มีข้อมูลเมตาที่แนบมากับข้อมูลที่คุณจัดเก็บเสมอ ประเภทขนาดความยาว blah blah blah
Marc B

cpython จัดสรรจากฮีปที่มีสัญญาณรบกวนขึ้นเนื่องจากอ็อบเจ็กต์เป็น malloc'd และเป็นอิสระ
tdelaney

ตัวเลข Python ไม่ใช่ข้อมูลง่ายๆ เป็นออบเจ็กต์ที่ใช้ระยะยาวในการเริ่มต้นจากนั้นเลื่อนระดับอัตโนมัติเป็นการแสดงลักษณะ BigNumber หากค่ามีขนาดใหญ่เกินไป
Gareth Latty

คำตอบ:


158

โพสต์ของคุณถามคำถามหลายประการ:

ตัวเลขที่ส่งกลับมาจากฟังก์ชันคืออะไร?

มันคือ " จำนวนเต็ม (หรือจำนวนเต็มยาว) ซึ่งรับประกันว่าจะไม่ซ้ำกันและคงที่สำหรับออบเจ็กต์นี้ตลอดอายุการใช้งาน " (Python Standard Library - Built-in Functions)ตัวเลขที่ไม่ซ้ำกัน ไม่มีอะไรมากและไม่มีอะไรน้อย คิดว่าเป็นหมายเลขประกันสังคมหรือหมายเลขรหัสพนักงานสำหรับวัตถุ Python

มันเหมือนกันกับที่อยู่หน่วยความจำใน C หรือไม่?

ตามแนวความคิดใช่เพราะพวกเขาทั้งสองได้รับการประกันว่าจะไม่เหมือนใครในจักรวาลตลอดช่วงชีวิตของพวกเขา และในการใช้งาน Python โดยเฉพาะอย่างยิ่งมันเป็นที่อยู่หน่วยความจำของวัตถุ C ที่เกี่ยวข้อง

ถ้าใช่ทำไมจำนวนจึงไม่เพิ่มขึ้นทันทีตามขนาดของชนิดข้อมูล (ฉันคิดว่ามันจะเป็น int)

เนื่องจากรายการไม่ใช่อาร์เรย์และองค์ประกอบรายการเป็นการอ้างอิงไม่ใช่วัตถุ

เราใช้id( )ฟังก์ชันจริงๆเมื่อไหร่?

แทบจะไม่เคย id()(หรือเทียบเท่า) ถูกใช้ในตัวisดำเนินการ


เราใช้ id () โดยปกติในการสาธิตเช่นที่นี่stackoverflow.com/questions/17246693/…
Nabin

51

นั่นคือเอกลักษณ์ของตำแหน่งของวัตถุในความทรงจำ ...

ตัวอย่างนี้อาจช่วยให้คุณเข้าใจแนวคิดมากขึ้นเล็กน้อย

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

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

> 1532352
> 1532352
> 1532352
> 1532352

สิ่งเหล่านี้ชี้ไปที่ตำแหน่งเดียวกันในหน่วยความจำซึ่งเป็นสาเหตุที่ค่าของมันเหมือนกัน ในตัวอย่าง1จะจัดเก็บเพียงครั้งเดียวและสิ่งอื่น ๆ ที่ชี้ไป1จะอ้างอิงตำแหน่งหน่วยความจำนั้น


10
แต่ถ้าคุณใช้ตัวเลขเกินช่วง -5 ถึง 256 คุณจะไม่ได้รับ id เดียวกันสำหรับตัวแปร fii
saurav

ที่น่าสนใจมาก คุณสามารถแบ่งปันเพิ่มเติมได้หรือไม่?
jouell

3
ฉันคิดว่าคำตอบนี้ทำให้เข้าใจผิดเนื่องจากไม่ถือเป็นจริงสำหรับตัวเลขส่วนใหญ่ ดู“คือ” ผู้ประกอบการทำงานโดยไม่คาดคิดกับจำนวนเต็ม
kevinji

9

id()ส่งคืนที่อยู่ของวัตถุที่อ้างอิง (ใน CPython) แต่ความสับสนของคุณมาจากข้อเท็จจริงที่ว่ารายการ python แตกต่างจากอาร์เรย์ C มาก ในรายการหลามองค์ประกอบทุกคนเป็นอ้างอิง ดังนั้นสิ่งที่คุณกำลังทำจึงคล้ายกับรหัส C นี้มาก:

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

กล่าวอีกนัยหนึ่งคุณกำลังพิมพ์ที่อยู่จากข้อมูลอ้างอิงไม่ใช่ที่อยู่ที่สัมพันธ์กับที่จัดเก็บรายการของคุณ

ในกรณีของฉันฉันพบว่าid()ฟังก์ชันนี้มีประโยชน์สำหรับการสร้างที่จับทึบแสงเพื่อกลับไปที่รหัส C เมื่อโทรpythonจาก C การทำเช่นนั้นคุณสามารถใช้พจนานุกรมเพื่อค้นหาวัตถุจากที่จับได้อย่างง่ายดายและรับประกันว่าจะไม่ซ้ำใคร


8

คำตอบของ Rob (โหวตมากที่สุดด้านบน) ถูกต้อง ฉันต้องการเพิ่มว่าในบางสถานการณ์การใช้ ID จะมีประโยชน์เนื่องจากช่วยให้สามารถเปรียบเทียบวัตถุและค้นหาว่าวัตถุใดอ้างถึงวัตถุของคุณ

ในภายหลังมักจะช่วยคุณเช่นในการดีบักจุดบกพร่องแปลก ๆ โดยที่วัตถุที่เปลี่ยนแปลงไม่ได้จะถูกส่งผ่านเป็นพารามิเตอร์เพื่อพูดคลาสและถูกกำหนดให้กับตัวแปรโลคัลในคลาส การกลายพันธุ์วัตถุเหล่านั้นจะกลายพันธุ์ตัวแปรในคลาส สิ่งนี้แสดงออกมาในพฤติกรรมแปลก ๆ ที่มีหลายสิ่งเปลี่ยนแปลงในเวลาเดียวกัน

เมื่อเร็ว ๆ นี้ฉันมีปัญหากับแอพ Python / Tkinter ที่การแก้ไขข้อความในช่องป้อนข้อความหนึ่งเปลี่ยนข้อความในอีกช่องหนึ่งตามที่ฉันพิมพ์ :)

นี่คือตัวอย่างวิธีที่คุณอาจใช้ function id () เพื่อติดตามว่าการอ้างอิงเหล่านั้นอยู่ที่ใด โดยวิธีทั้งหมดนี้ไม่ใช่วิธีแก้ปัญหาที่ครอบคลุมทุกกรณี แต่คุณจะได้รับแนวคิด อีกครั้งมีการใช้ ID ในพื้นหลังและผู้ใช้ไม่เห็น:

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

เอาท์พุท:

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

ขีดล่างในชื่อตัวแปรใช้เพื่อป้องกันการจับคู่ชื่อ ฟังก์ชันใช้อาร์กิวเมนต์ "จากที่ใด" เพื่อให้คุณสามารถแจ้งให้พวกเขาทราบว่าจะเริ่มค้นหาข้อมูลอ้างอิงได้จากที่ใด อาร์กิวเมนต์นี้เต็มไปด้วยฟังก์ชันที่แสดงรายชื่อทั้งหมดในเนมสเปซที่กำหนด Globals () เป็นฟังก์ชันหนึ่ง


คำอธิบายสุดยอด!
Neeraj Verma

5

ฉันเริ่มต้นด้วย python และฉันใช้ id เมื่อฉันใช้เชลล์แบบโต้ตอบเพื่อดูว่าตัวแปรของฉันถูกกำหนดให้กับสิ่งเดียวกันหรือว่ามันดูเหมือนกัน

ทุกค่าคือ id ซึ่งเป็นหมายเลขเฉพาะที่เกี่ยวข้องกับตำแหน่งที่เก็บไว้ในหน่วยความจำของคอมพิวเตอร์


5

หากคุณใช้ python 3.4.1 คุณจะได้รับคำตอบอื่นสำหรับคำถามของคุณ

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

ผลตอบแทน:

1705950792   
1705950808  # increased by 16   
1705950824  # increased by 16

จำนวนเต็ม-5จะ256มี id คงที่และเมื่อค้นหาหลาย ๆ ครั้ง id ของมันจะไม่เปลี่ยนแปลงซึ่งแตกต่างจากตัวเลขอื่น ๆ ก่อนหรือหลังที่มี id ต่างกันทุกครั้งที่คุณพบ ตัวเลขจาก-5การ256มี id 16ของในการสั่งซื้อที่เพิ่มขึ้นและความแตกต่างกัน

หมายเลขที่ส่งคืนโดยid()ฟังก์ชันเป็นรหัสเฉพาะที่กำหนดให้กับแต่ละรายการที่จัดเก็บในหน่วยความจำและเป็นการเปรียบเทียบที่ชาญฉลาดเช่นเดียวกับตำแหน่งหน่วยความจำใน C


2

คำตอบคือไม่เคยสวยมาก ID ส่วนใหญ่จะใช้ภายใน Python

โปรแกรมเมอร์ Python โดยเฉลี่ยอาจไม่จำเป็นต้องใช้id()ในโค้ดของพวกเขา


3
บางทีฉันอาจจะไม่ธรรมดา แต่ฉันก็ใช้id()ไม่น้อย กรณีการใช้งานสองกรณีที่อยู่ด้านบนสุดของหัวของฉัน: คำสั่งเอกลักษณ์ (รีดด้วยมือเฉพาะกิจ) และแบบกำหนดเองrepr()สำหรับออบเจ็กต์ที่เอกลักษณ์มีความสำคัญ แต่ค่าเริ่มต้นreprไม่เหมาะสม

5
@ เดลแนนฉันจะไม่เถียงว่าเป็นกรณีทั่วไป
Gareth Latty

2

ตัวisดำเนินการใช้เพื่อตรวจสอบว่าวัตถุสองชิ้นเหมือนกันหรือไม่ (ตรงข้ามกับสิ่งที่เท่าเทียมกัน) ค่าจริงที่ส่งกลับมาid()นั้นค่อนข้างไม่เคยใช้กับอะไรเลยเพราะมันไม่มีความหมายจริงๆและขึ้นอยู่กับแพลตฟอร์ม


2

เป็นที่อยู่ของวัตถุในหน่วยความจำตรงตามที่เอกสารบอก อย่างไรก็ตามมีข้อมูลเมตาที่แนบมาด้วยจำเป็นต้องมีคุณสมบัติของวัตถุและตำแหน่งในหน่วยความจำเพื่อจัดเก็บข้อมูลเมตา ดังนั้นเมื่อคุณสร้างตัวแปรที่เรียกว่ารายการคุณยังสร้างข้อมูลเมตาสำหรับรายการและองค์ประกอบต่างๆ

ดังนั้นหากคุณไม่ได้เป็นผู้เชี่ยวชาญด้านภาษาคุณจะไม่สามารถระบุรหัสขององค์ประกอบถัดไปของรายการของคุณตามองค์ประกอบก่อนหน้าได้เนื่องจากคุณไม่ทราบว่าภาษานั้นจัดสรรพร้อมกับองค์ประกอบใดบ้าง


1
id()อันที่จริงเป็นกูรูงูใหญ่จะไม่ใช้มากทำนายของวัตถุใด ๆ คุณต้องทำความคุ้นเคยอย่างใกล้ชิดกับผู้จัดการหน่วยความจำ (พหูพจน์!) ที่เป็นปัญหารู้สถานะที่แน่นอนของพวกเขาในบางช่วงเวลาและรู้ลำดับที่แน่นอนที่วัตถุได้รับการจัดสรร กล่าวอีกนัยหนึ่ง: จะไม่เกิดขึ้น

คุณเป็นกูรู Python อย่างแท้จริงหากคุณรู้ความแตกต่างทั้งหมดรวมถึงผู้จัดการหน่วยความจำ
Lajos Arpad

1
การรู้จัก Python และการรู้จักการนำไปใช้งาน (เช่น CPython) เป็นสองสิ่งที่แตกต่างกันอย่างสิ้นเชิง และถึงแม้การรู้ CPython จากภายนอกก็ไม่ช่วยได้เนื่องจากมีตัวจัดการหน่วยความจำหลายตัวที่ CPython เรียกใช้สิ่งนั้นไม่ได้เป็นส่วนหนึ่งของ CPython แต่เป็นส่วนหนึ่งของระบบปฏิบัติการที่เกี่ยวข้อง และอย่างที่ฉันเคยพูดไปแล้วแม้ว่าการรู้ว่าสิ่งที่ไม่ใช่ Python ทั้งหมดนี้จะไม่ช่วยคุณได้เนื่องจากที่อยู่จริงขึ้นอยู่กับสถานะรันไทม์ของตัวจัดการหน่วยความจำและบางครั้งก็เป็นแบบสุ่ม

1
ไม่ต้องพูดถึงคงไม่มีประโยชน์ที่จะรู้เนื่องจากการพึ่งพาสิ่งดังกล่าวจะต้องอาศัยรายละเอียดการนำไปใช้งานและด้วยเหตุนี้จึงเปราะบางและไม่ยืดหยุ่น
Gareth Latty

2

ฉันมีความคิดที่จะใช้มูลค่าid()ในการบันทึก
ราคาถูกและค่อนข้างสั้น
ในกรณีของฉันฉันใช้ทอร์นาโดและid()ต้องการมีจุดยึดเพื่อจัดกลุ่มข้อความที่กระจัดกระจายและผสมกันบนไฟล์โดยเว็บซ็อกเก็ต


0

ใน python 3 id ถูกกำหนดให้กับค่าไม่ใช่ตัวแปร ซึ่งหมายความว่าหากคุณสร้างสองฟังก์ชันดังต่อไปนี้ id ทั้งสามจะเหมือนกัน

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

แม้ว่าสิ่งนี้จะขัดแย้งกับคำอธิบายก่อนหน้า แต่ดูเหมือนว่าจะเกิดขึ้นและฉันไม่รู้ว่าทำไม คำอธิบายใด ๆ เช่น x [0] = "abc" x [1] = "def" q = ["abc", "def"] Id (x) == Id (q) เป็น True เหตุบังเอิญ?
VMMF

0

ฉันสายไปหน่อยแล้วจะพูดถึง Python3 เพื่อให้เข้าใจว่า id () คืออะไรและทำงานอย่างไร (และ Python) ให้พิจารณาตัวอย่างถัดไป:

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

คุณต้องคิดว่าทุกสิ่งทางด้านขวาเป็นวัตถุ ทุกครั้งที่คุณทำการมอบหมาย - คุณสร้างวัตถุใหม่และนั่นหมายถึงรหัสใหม่ ตรงกลางคุณจะเห็นออบเจ็กต์ "wild" ซึ่งสร้างขึ้นสำหรับฟังก์ชันเท่านั้น - id (1000) ดังนั้นอายุการใช้งานเป็นเพียงสำหรับบรรทัดของรหัสนั้น หากคุณตรวจสอบบรรทัดถัดไปคุณจะเห็นว่าเมื่อเราสร้างตัวแปร x ใหม่จะมี id เดียวกันกับวัตถุเสริมนั้น มันใช้งานได้ดีเหมือนที่อยู่หน่วยความจำ


0

ระวัง (เกี่ยวกับคำตอบด้านล่าง) ... นั่นเป็นความจริงเพียงเพราะ 123 อยู่ระหว่าง -5 ถึง 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
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.