Hàm id () được sử dụng để làm gì?


99

Tôi đã đọc tài liệu Python 2 và nhận thấy id()chức năng:

Trả lại "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 thời gian tồn tại của nó. Hai đối tượng có vòng đời không trùng lặp có thể có cùng giá trị id ().

Chi tiết triển khai CPython: Đây là địa chỉ của đối tượng trong bộ nhớ.

Vì vậy, tôi đã thử nghiệm bằng cách sử dụng id()với một danh sách:

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

Số nguyên được trả về từ hàm là gì? Nó có đồng nghĩa với địa chỉ bộ nhớ trong C không? Nếu vậy, tại sao số nguyên không tương ứng với kích thước của kiểu dữ liệu?

Khi nào được id()sử dụng trong thực tế?


4
Chỉ vì bạn lưu trữ (giả sử) một int 32bit trong cấu trúc dữ liệu bằng ngôn ngữ kịch bản không có nghĩa là bạn sẽ sử dụng thêm bộ nhớ 32bit. LUÔN LUÔN có siêu dữ liệu được đính kèm với BẤT KỲ dữ liệu nào bạn lưu trữ. loại, kích thước, chiều dài, blah blah blah.
Marc B

cpython phân bổ từ một đống được xáo trộn khi các đối tượng bị sai và tự do.
tdelaney

Số trong Python không phải là những phần dữ liệu đơn giản. Chúng là các đối tượng sử dụng long trong nội bộ để bắt đầu, sau đó tự động quảng cáo thành biểu diễn kiểu BigNumber nếu giá trị quá lớn.
Gareth Latty

Câu trả lời:


156

Bài đăng của bạn đặt một số câu hỏi:

Số trả về từ hàm là gì?

Nó 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 thời gian tồn tại của nó. " (Thư viện chuẩn Python - Các hàm dựng sẵn) Một số duy nhất. Không hơn không kém. Hãy coi nó như một số an sinh xã hội hoặc số id nhân viên cho các đối tượng Python.

Địa chỉ bộ nhớ trong C có giống nhau không?

Về mặt khái niệm, vâng, cả hai đều được đảm bảo là duy nhất trong vũ trụ của chúng trong suốt thời gian tồn tại. Và trong một triển khai cụ thể của Python, nó thực sự là địa chỉ bộ nhớ của đối tượng C tương ứng.

Nếu có, tại sao số lượng không tăng ngay lập tức theo kích thước của kiểu dữ liệu (tôi giả sử rằng nó sẽ là int)?

Bởi vì danh sách không phải là một mảng và phần tử danh sách là một tham chiếu, không phải một đối tượng.

Khi nào chúng ta thực sự sử dụng id( )chức năng?

Hầu như không bao giờ. id()(hoặc tương đương) được sử dụng trong istoán tử.


Chúng tôi sử dụng id () thường trong mục đích cuộc biểu tình như ở đây stackoverflow.com/questions/17246693/...
Nabin

49

Đó là nhận dạng vị trí của đối tượng trong bộ nhớ ...

Ví dụ này có thể giúp bạn hiểu khái niệm nhiều hơn một chút.

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

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

> 1532352
> 1532352
> 1532352
> 1532352

Tất cả những thứ này đều trỏ đến cùng một vị trí trong bộ nhớ, đó là lý do tại sao giá trị của chúng giống nhau. Trong ví dụ, 1chỉ được lưu trữ một lần và bất kỳ thứ gì khác trỏ đến 1sẽ tham chiếu đến vị trí bộ nhớ đó.


9
Nhưng nếu bạn sử dụng các số vượt quá phạm vi -5 đến 256, bạn sẽ không nhận được cùng một id cho biến fii.
saurav

điều đó cực kỳ thú vị. Bạn có thể chia sẻ thêm được không?
jouell

3
Tôi nghĩ câu trả lời này là sai vì điều này không đúng với hầu hết các con số; toán tử see "is" hoạt động không mong muốn với các số nguyên .
kevinji

8

id()không trả về địa chỉ của đối tượng đang được tham chiếu (trong CPython), nhưng sự nhầm lẫn của bạn đến từ thực tế là danh sách python rất khác với mảng C. Trong danh sách python, mọi phần tử là một tham chiếu . Vì vậy, những gì bạn đang làm tương tự hơn nhiều với mã C này:

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

Nói cách khác, bạn đang in địa chỉ từ tham chiếu chứ không phải địa chỉ liên quan đến nơi danh sách của bạn được lưu trữ.

Trong trường hợp của tôi, tôi thấy id()chức năng này rất tiện lợi để tạo các chốt điều khiển mờ để quay lại mã C khi gọi pythontừ C. Làm điều đó, bạn có thể dễ dàng sử dụng từ điển để tra cứu đối tượng từ tay cầm của nó và nó được đảm bảo là duy nhất.


7

Câu trả lời của Rob (được bình chọn nhiều nhất ở trên) là đúng. Tôi muốn nói thêm rằng trong một số trường hợp, sử dụng ID rất hữu ích vì nó cho phép so sánh các đối tượng và tìm đối tượng nào tham chiếu đến đối tượng của bạn.

Ví dụ sau này thường giúp bạn gỡ lỗi các lỗi lạ trong đó các đối tượng có thể thay đổi được truyền dưới dạng tham số để nói các lớp và được gán cho các vars cục bộ trong một lớp. Việc thay đổi các đối tượng đó sẽ làm thay đổi các vars trong một lớp. Điều này thể hiện ở hành vi kỳ lạ khi nhiều thứ thay đổi cùng một lúc.

Gần đây, tôi đã gặp sự cố này với ứng dụng Python / Tkinter trong đó việc chỉnh sửa văn bản trong một trường nhập văn bản đã thay đổi văn bản trong một trường khác khi tôi nhập :)

Đây là một ví dụ về cách bạn có thể sử dụng hàm id () để theo dõi các tham chiếu đó ở đâu. Bằng mọi cách, đây không phải là một giải pháp bao gồm tất cả các trường hợp có thể xảy ra, nhưng bạn có ý tưởng. Một lần nữa ID được sử dụng trong nền và người dùng không nhìn thấy chúng:

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

ĐẦU RA:

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

Dấu gạch dưới trong tên biến được sử dụng để ngăn chặn các vùng tên. Các hàm sử dụng đối số "từ đâu" để bạn có thể cho chúng biết bắt đầu tìm kiếm tham chiếu từ đâu. Đối số này được điền bởi một hàm liệt kê tất cả các tên trong một vùng tên nhất định. Globals () là một trong những hàm như vậy.


Lời giải thích tuyệt vời!
Neeraj Verma

5

Tôi đang bắt đầu với python và tôi sử dụng id khi tôi sử dụng trình bao tương tác để xem liệu các biến của tôi có được gán cho cùng một thứ hay không hay chúng trông giống nhau.

Mỗi giá trị là một id, là một số duy nhất liên quan đến nơi nó được lưu trữ trong bộ nhớ của máy tính.


5

Nếu bạn đang sử dụng python 3.4.1 thì bạn sẽ nhận được một câu trả lời khác cho câu hỏi của mình.

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

trả lại:

1705950792   
1705950808  # increased by 16   
1705950824  # increased by 16

Các số nguyên -5để 256có một id liên tục, và vào việc tìm kiếm nó nhiều lần id của nó không thay đổi, không giống như tất cả các số khác trước hoặc sau nó có id khác nhau là mỗi khi bạn tìm thấy nó. Những con số từ -5để 256có id trong thứ tự tăng dần và khác nhau bởi 16.

Số được id()hàm trả về là một id duy nhất được cấp cho mỗi mục được lưu trong bộ nhớ và nó tương tự như vị trí bộ nhớ trong C.


2

Câu trả lời là không bao giờ. ID chủ yếu được sử dụng trong nội bộ Python.

Các lập trình viên Python trung bình có thể sẽ không bao giờ cần sử dụng id()mã của họ.


3
Có lẽ tôi không phải là trung bình, nhưng tôi sử dụng id()khá ít. Hai trường hợp sử dụng ngoài đầu tôi: Một mệnh lệnh nhận dạng (cuộn bằng tay, đặc biệt) và một tùy chỉnh repr()cho một đối tượng mà danh tính quan trọng nhưng mặc định reprkhông phù hợp.

5
@delnan Tôi sẽ không tranh luận đó là những trường hợp phổ biến.
Gareth Latty

2

Các isnhà khai thác sử dụng nó để kiểm tra xem hai đối tượng giống hệt nhau (như trái ngược với bình đẳng). Giá trị thực tế được trả về id()hầu như không bao giờ được sử dụng cho bất cứ việc gì vì nó không thực sự có ý nghĩa và nó phụ thuộc vào nền tảng.


2

Nó là địa chỉ của đối tượng trong bộ nhớ, chính xác như tài liệu nói. Tuy nhiên, nó có siêu dữ liệu gắn liền với nó, các thuộc tính của đối tượng và vị trí trong bộ nhớ là cần thiết để lưu trữ siêu dữ liệu. Vì vậy, khi bạn tạo biến được gọi là danh sách, bạn cũng tạo siêu dữ liệu cho danh sách và các phần tử của nó.

Vì vậy, trừ khi bạn là một chuyên gia về ngôn ngữ, bạn không thể xác định id của phần tử tiếp theo trong danh sách của bạn dựa trên phần tử trước đó, bởi vì bạn không biết ngôn ngữ phân bổ những gì cùng với các phần tử.


1
Trên thực tế, trở thành một chuyên gia Python sẽ không có ích gì nhiều khi dự đoán bất kỳ đối tượng nào id(). Bạn cần phải quen thuộc với các trình quản lý bộ nhớ (số nhiều!) Được đề cập, biết chính xác trạng thái của chúng tại một thời điểm nào đó và biết chính xác thứ tự mà các đối tượng đã được cấp phát. Nói cách khác: Sẽ không xảy ra.

Bạn là một chuyên gia Python tuyệt đối nếu bạn hoàn toàn biết tất cả các sắc thái của nó, bao gồm các trình quản lý bộ nhớ có thể có.
Lajos Arpad

1
Biết Python và biết một triển khai cụ thể (ví dụ: CPython) là hai điều hoàn toàn khác nhau. Và ngay cả khi biết CPython từ trong ra ngoài sẽ không giúp ích được gì, vì có một số trình quản lý bộ nhớ gọi CPython không phải là một phần của CPython mà là một phần của hệ điều hành tương ứng. Và như tôi đã nói trước đây, ngay cả khi biết tất cả những thứ không phải Python này sẽ không giúp ích được gì cho bạn, vì các địa chỉ thực tế phụ thuộc vào trạng thái thời gian chạy của trình quản lý bộ nhớ và đôi khi thậm chí còn được ngẫu nhiên hóa.

1
Chưa kể, sẽ vô ích nếu biết, vì dựa vào một thứ như vậy sẽ dựa vào một chi tiết thực hiện và do đó rất mỏng manh và không linh hoạt.
Gareth Latty

2

Tôi có một ý tưởng để sử dụng giá trị của id()đăng nhập.
Nó rẻ để có được và nó khá ngắn.
Trong trường hợp của tôi, tôi sử dụng tornado và id()muốn có một liên kết để nhóm các thư nằm rải rác và trộn lẫn trên tệp bằng ổ cắm web.


0

Kể từ trong python 3, id được gán cho một giá trị không phải là một biến. Điều này có nghĩa là nếu bạn tạo hai hàm như bên dưới, cả ba id đều giống nhau.

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

Mặc dù điều này mâu thuẫn với những lời giải thích trước đây, nó dường như xảy ra và tôi không biết tại sao. Bất kỳ lời giải thích? Ví dụ: x [0] = "abc" x [1] = "def" q = ["abc", "def"]. Id (x) == Id (q) là True. Sự trùng hợp ngẫu nhiên?
VMMF

0

Tôi hơi muộn một chút và tôi sẽ nói về Python3. Để hiểu id () là gì và nó (và Python) hoạt động như thế nào, hãy xem xét ví dụ tiếp theo:

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

Bạn cần nghĩ về mọi thứ ở phía bên phải như các đối tượng. Mỗi khi bạn thực hiện nhiệm vụ - bạn tạo đối tượng mới và điều đó có nghĩa là id mới. Ở giữa, bạn có thể thấy một đối tượng "hoang dã" chỉ được tạo cho hàm - id (1000). Vì vậy, thời gian tồn tại chỉ dành cho dòng mã đó. Nếu bạn kiểm tra dòng tiếp theo - bạn sẽ thấy rằng khi chúng ta tạo biến mới x, nó có cùng id với đối tượng hoang dã đó. Nó hoạt động giống như địa chỉ bộ nhớ.


0

Hãy cẩn thận (liên quan đến câu trả lời ngay bên dưới) ... Điều đó chỉ đúng vì 123 nằm giữa -5 và 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
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.