Câu trả lời:
Các nhãn hiệu Python có này để nói về id()
:
Trả về "danh tính" của một đối tượng. Đây là một số nguyên (hoặc số nguyên dài) được đảm bảo là duy nhất và không đổi cho đối tượng này trong suốt vòng đời của nó. Hai đối tượng có tuổi thọ không chồng lấp có thể có cùng giá trị id (). (Ghi chú thực hiện: đây là địa chỉ của đối tượng.)
Vì vậy, trong CPython, đây sẽ là địa chỉ của đối tượng. Mặc dù vậy, không có sự đảm bảo nào cho bất kỳ trình thông dịch Python nào khác.
Lưu ý rằng nếu bạn đang viết tiện ích mở rộng C, bạn có toàn quyền truy cập vào phần bên trong của trình thông dịch Python, bao gồm quyền truy cập trực tiếp vào địa chỉ của các đối tượng.
lifetime
(và ý nghĩa của cả đời đối với overlap/not overlap
) là gì trong bối cảnh này?
Bạn có thể thực hiện lại repr mặc định theo cách này:
def __repr__(self):
return '<%s.%s object at %s>' % (
self.__class__.__module__,
self.__class__.__name__,
hex(id(self))
)
return object.__repr__(self)
hoặc thậm chí chỉ cần làm object.__repr__(obj)
bất cứ khi nào bạn cần thay vì tạo một lớp mới
__repr__ = object.__repr__
và gần như không phải là bằng chứng ngu ngốc, vì có nhiều tình huống mà việc này không hiệu quả, ví dụ như __getattribute__
việc thực thi bị ghi đè hoặc không phải CPython trong đó id không vị trí bộ nhớ. Nó cũng không điền vào z, vì vậy bạn sẽ phải xử lý nếu hệ thống là 64 bit và thêm các số 0 nếu cần.
Chỉ dùng
id(object)
id()
@JLT
Có một vài vấn đề ở đây không được đề cập trong bất kỳ câu trả lời nào khác.
Đầu tiên, id
chỉ trả về:
bản sắc của người Viking về một đối tượng. Đây là một số nguyên (hoặc số nguyên dài) được đảm bảo là duy nhất và không đổi cho đối tượng này trong suốt vòng đời của nó. Hai đối tượng có tuổi thọ không chồng chéo có thể có cùng
id()
giá trị.
Trong CPython, điều này xảy ra là con trỏ tới PyObject
đại diện cho đối tượng trong trình thông dịch, đó là điều tương tự nhưobject.__repr__
hiển thị. Nhưng đây chỉ là một chi tiết triển khai của CPython, không phải là điều gì đó đúng với Python nói chung. Jython không xử lý các con trỏ, nó xử lý các tham chiếu Java (dĩ nhiên JVM có thể đại diện cho các con trỏ, nhưng bạn không thể nhìn thấy các con trỏ đó và sẽ không muốn, bởi vì GC được phép di chuyển chúng xung quanh). PyPy cho phép các loại khác nhau có các loại khác nhau id
, nhưng chung nhất chỉ là một chỉ mục vào một bảng các đối tượng bạn đã gọiid
trên, rõ ràng sẽ không phải là một con trỏ. Tôi không chắc chắn về IronPython, nhưng tôi nghi ngờ nó giống Jython hơn là CPython về vấn đề này. Vì vậy, trong hầu hết các triển khai Python, không có cách nào để hiển thị bất cứ thứ gì xuất hiện trong đó repr
và không sử dụng nếu bạn đã làm.
Nhưng nếu bạn chỉ quan tâm đến CPython thì sao? Rốt cuộc, đó là một trường hợp khá phổ biến.
Chà, trước tiên, bạn có thể nhận thấy đó id
là một số nguyên; * nếu bạn muốn 0x2aba1c0cf890
chuỗi đó thay vì số 46978822895760
, bạn sẽ phải tự định dạng nó. Dưới sự bao trùm, tôi tin object.__repr__
là cuối cùng sử dụng printf
's %p
định dạng mà bạn không cần phải từ Python ... nhưng bạn luôn có thể làm điều này:
format(id(spam), '#010x' if sys.maxsize.bit_length() <= 32 else '#18x')
* Trong 3.x, đó là một int
. Trong 2.x, đó là int
nếu nó đủ lớn để chứa một con trỏ, điều này có thể không phải do vấn đề về số lượng đã ký trên một số nền tảng long
.
Có điều gì bạn có thể làm với những con trỏ này ngoài việc in chúng ra không? Chắc chắn (một lần nữa, giả sử bạn chỉ quan tâm đến CPython).
Tất cả các hàm API C đều đưa một con trỏ đến một PyObject
hoặc một loại liên quan. Đối với những loại liên quan, bạn chỉ có thể gọi PyFoo_Check
để đảm bảo rằng nó thực sự là một Foo
đối tượng, sau đó sử dụng (PyFoo *)p
. Vì vậy, nếu bạn đang viết một phần mở rộng C, id
thì đó chính xác là những gì bạn cần.
Điều gì xảy ra nếu bạn đang viết mã Python thuần túy? Bạn có thể gọi các chức năng chính xác tương tự với pythonapi
từ ctypes
.
Cuối cùng, một vài câu trả lời khác đã đưa ra ctypes.addressof
. Điều đó không liên quan ở đây. Điều này chỉ hoạt động cho ctypes
các đối tượng như c_int32
(và có thể một vài đối tượng giống như bộ nhớ đệm, như các đối tượng được cung cấp bởi numpy
). Và, ngay cả ở đó, nó không cung cấp cho bạn địa chỉ của c_int32
giá trị, nó sẽ cung cấp cho bạn địa chỉ của cấp độ C int32
mà c_int32
kết thúc.
Điều đó đang được nói, thường xuyên hơn không, nếu bạn thực sự nghĩ rằng bạn cần địa chỉ của một cái gì đó, bạn đã không muốn một đối tượng Python nguyên gốc ở nơi đầu tiên, bạn muốn có một ctypes
đối tượng.
id
cách sử dụng chúng để giữ các giá trị có thể thay đổi trong một seen
tập hợp hoặc một cache
dict không phụ thuộc vào bất kỳ cách nào để id
trở thành một con trỏ hoặc liên quan đến bất kỳ cách nào repr
. Đó chính xác là lý do tại sao mã như vậy hoạt động trong tất cả các triển khai Python, thay vì chỉ hoạt động trong CPython.
id
nó, nhưng ý tôi là ngay cả trong java bạn cũng có thể lấy địa chỉ của đối tượng, có vẻ lạ là không có cách nào trong (C) Python vì người ta có gc thực sự ổn định mà không di chuyển các đối tượng do đó địa chỉ vẫn giữ nguyên
id
một đối tượng, cho dù đó có phải là địa chỉ hay không. Ví dụ, trong PyPy, id
vẫn hữu dụng như một khóa trong CPython, mặc dù nó thường chỉ là một chỉ mục vào một bảng ẩn trong triển khai, nhưng một con trỏ sẽ vô dụng, vì (như Java) đối tượng có thể được di chuyển vào ký ức.
id
đối tượng là con trỏ đến vị trí của đối tượng trong bộ nhớ. Vì vậy, nếu bạn có bất kỳ việc sử dụng nào cho giá trị con trỏ (điều mà bạn gần như không bao giờ làm, như được giải thích trong câu trả lời) trong mã dành riêng cho CPython, có một cách để làm cho nó được ghi lại và đảm bảo hoạt động.
Chỉ để đáp lại Torsten, tôi đã không thể gọi addressof()
một đối tượng trăn thông thường. Hơn nữa , id(a) != addressof(a)
. Đây là trong CPython, không biết về bất cứ điều gì khác.
>>> from ctypes import c_int, addressof
>>> a = 69
>>> addressof(a)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: invalid type
>>> b = c_int(69)
>>> addressof(b)
4300673472
>>> id(b)
4300673392
Với ctypes , bạn có thể đạt được điều tương tự với
>>> import ctypes
>>> a = (1,2,3)
>>> ctypes.addressof(a)
3077760748L
Tài liệu:
addressof(C instance) -> integer
Trả về địa chỉ của bộ đệm nội bộ C
Lưu ý rằng trong CPython, hiện tại id(a) == ctypes.addressof(a)
, nhưng ctypes.addressof
nên trả về địa chỉ thực cho mỗi lần triển khai Python, nếu
Chỉnh sửa : thêm thông tin về tính độc lập của trình thông dịch của ctypes
TypeError: invalid type
khi tôi thử nó với Python 3.4.
Bạn có thể nhận được một cái gì đó phù hợp cho mục đích đó với:
id(self)
Tôi biết đây là một câu hỏi cũ nhưng nếu bạn vẫn đang lập trình, trong python 3 ngày nay ... tôi thực sự thấy rằng nếu đó là một chuỗi, thì có một cách thực sự dễ dàng để làm điều này:
>>> spam.upper
<built-in method upper of str object at 0x1042e4830>
>>> spam.upper()
'YO I NEED HELP!'
>>> id(spam)
4365109296
chuyển đổi chuỗi cũng không ảnh hưởng đến vị trí trong bộ nhớ:
>>> spam = {437 : 'passphrase'}
>>> object.__repr__(spam)
'<dict object at 0x1043313f0>'
>>> str(spam)
"{437: 'passphrase'}"
>>> object.__repr__(spam)
'<dict object at 0x1043313f0>'
Mặc dù đúng là id(object)
có địa chỉ của đối tượng trong triển khai CPython mặc định, nhưng điều này thường vô dụng ... bạn không thể làm gì với địa chỉ từ mã Python thuần túy.
Lần duy nhất bạn thực sự có thể sử dụng địa chỉ là từ thư viện C mở rộng ... trong trường hợp đó là việc lấy địa chỉ của đối tượng là không quan trọng vì các đối tượng Python luôn được truyền xung quanh dưới dạng con trỏ C.
ctypes
bộ công cụ tích hợp trong Thư viện chuẩn. Trong trường hợp nào bạn có thể làm tất cả mọi thứ với địa chỉ :)