Địa chỉ bộ nhớ trong Python
Tôi sẽ thảo luận về 'Cách tìm địa chỉ bộ nhớ của một biến' trong Python. Sau đây tôi sẽ hướng dẫn chi tiết cho các bạn cách tìm địa chỉ của các biến Show
Tìm địa chỉ của một biến bằng id() trong PythonHãy xem xét một người P sống ở Kolkata, nếu chúng ta muốn lấy địa chỉ của P, thì đó sẽ là Kolkata
Ví dụ var1 = 10 print(id(var1)) var2 = 12 print(id(var2)) Output:
2037008656
2037008688
def sum(var1,var2): return var1+var2 print("Address of funtion sum: ",id(sum)) Output:
Address of funtion sum: 55575944 ⇒Bạn cũng có thể sử dụng id() với đối tượng lớp, nó sẽ cung cấp tham chiếu của đối tượng đó
var1 = 2.60 print(hex(id(var1))) # print the address of var1 in hexadecimal format var2 = 3.90 print(hex(id(var2))) #print the address of var2 in hexadecimal format str1="Hello" print(hex(id(str1))) #print the address of str1 in hexadecimal format Output: '0x353a208' '0x3500588' '0x352f180' Do đó bạn có thể sử dụng id() để tìm địa chỉ của các biến trong Python Cũng đọc. Hàm id() trong Python Một phản hồi cho “Tìm địa chỉ bộ nhớ của một biến trong Python”
Để lại một câu trả lờiĐịa chỉ email của bạn sẽ không được công bố. Các trường bắt buộc được đánh dấu * Nhận xét * Tên * Email * Vui lòng bật JavaScript để gửi biểu mẫu nàyNếu bạn đã từng làm việc với các ngôn ngữ cấp thấp hơn như C hoặc C++, thì có lẽ bạn đã nghe nói về con trỏ. Con trỏ cho phép bạn tạo hiệu quả cao trong các phần mã của mình. Chúng cũng gây nhầm lẫn cho người mới bắt đầu và có thể dẫn đến các lỗi quản lý bộ nhớ khác nhau, ngay cả đối với các chuyên gia. Vậy chúng ở đâu trong Python và làm cách nào bạn có thể mô phỏng con trỏ trong Python? Con trỏ được sử dụng rộng rãi trong C và C++. Về cơ bản, chúng là các biến chứa địa chỉ bộ nhớ của một biến khác. Để ôn lại về con trỏ, bạn có thể cân nhắc xem phần tổng quan này về Con trỏ C Trong bài viết này, bạn sẽ hiểu rõ hơn về mô hình đối tượng của Python và tìm hiểu lý do tại sao con trỏ trong Python không thực sự tồn tại. Đối với những trường hợp bạn cần bắt chước hành vi của con trỏ, bạn sẽ học cách mô phỏng con trỏ trong Python mà không gặp cơn ác mộng về quản lý bộ nhớ Trong bài viết này, bạn sẽ
Ghi chú. Trong bài viết này, “Python” sẽ đề cập đến việc triển khai tham chiếu Python trong C, hay còn gọi là CPython. Vì bài viết thảo luận về một số phần bên trong của ngôn ngữ, những ghi chú này đúng với CPython 3. 7 nhưng có thể không đúng trong các lần lặp lại ngôn ngữ trong tương lai hoặc quá khứ Tải xuống miễn phí. Nhận một chương mẫu từ Thủ thuật Python. Cuốn sách chỉ cho bạn các phương pháp hay nhất về Python với các ví dụ đơn giản mà bạn có thể áp dụng ngay lập tức để viết mã Pythonic + đẹp hơn Tại sao Python không có con trỏ?sự thật là tôi không biết. Con trỏ trong Python có thể tồn tại tự nhiên không? . Con trỏ khuyến khích những thay đổi tiềm ẩn hơn là rõ ràng. Thông thường, chúng phức tạp thay vì đơn giản, đặc biệt là đối với người mới bắt đầu. Tệ hơn nữa, họ cầu xin những cách để tự bắn vào chân mình, hoặc làm điều gì đó thực sự nguy hiểm như đọc từ một phần ký ức mà bạn không được phép đọc. Python có xu hướng cố gắng trừu tượng hóa các chi tiết triển khai như địa chỉ bộ nhớ từ người dùng của nó. Python thường tập trung vào khả năng sử dụng thay vì tốc độ. Kết quả là, con trỏ trong Python không thực sự có ý nghĩa. Mặc dù vậy, đừng sợ, theo mặc định, Python cung cấp cho bạn một số lợi ích của việc sử dụng con trỏ Hiểu con trỏ trong Python yêu cầu một đường vòng ngắn vào chi tiết triển khai của Python. Cụ thể, bạn sẽ cần phải hiểu
Giữ địa chỉ bộ nhớ của bạn và bắt đầu Loại bỏ các quảng cáoCác đối tượng trong PythonTrong Python, mọi thứ đều là đối tượng. Để chứng minh, bạn có thể mở REPL và khám phá bằng cách sử dụng 2>>>
Mã này cho bạn thấy rằng mọi thứ trong Python thực sự là một đối tượng. Mỗi đối tượng chứa ít nhất ba mẩu dữ liệu
Dành cho quản lý bộ nhớ. Để có cái nhìn sâu hơn về nội dung quản lý bộ nhớ trong Python, bạn có thể đọc Quản lý bộ nhớ trong Python Loại được sử dụng ở lớp CPython để đảm bảo an toàn cho loại trong thời gian chạy. Cuối cùng, có giá trị, là giá trị thực được liên kết với đối tượng Mặc dù không phải tất cả các đối tượng đều giống nhau. Có một điểm khác biệt quan trọng khác mà bạn cần hiểu. đối tượng bất biến vs đối tượng có thể thay đổi. Hiểu được sự khác biệt giữa các loại đối tượng thực sự giúp làm rõ lớp đầu tiên của hành tây đó là con trỏ trong Python Đối tượng bất biến và có thể thay đổiTrong Python, có hai loại đối tượng
Hiểu sự khác biệt này là chìa khóa đầu tiên để điều hướng bối cảnh của các con trỏ trong Python. Đây là bảng phân tích các loại phổ biến và liệu chúng có thể thay đổi hay không thay đổi LoạiKhông thể thay đổi? 3Có 4Có 5Có 6Có 7Có 8Có 9CóOutput:
2037008656
2037008688
60KhôngOutput:
2037008656
2037008688
61KhôngOutput:
2037008656
2037008688
62KhôngNhư bạn có thể thấy, rất nhiều kiểu nguyên thủy thường được sử dụng là bất biến. Bạn có thể tự chứng minh điều này bằng cách viết một số Python. Bạn sẽ cần một vài công cụ từ thư viện chuẩn Python
Một lần nữa, bạn có thể sử dụng chúng trong môi trường REPL >>> def sum(var1,var2): return var1+var2 print("Address of funtion sum: ",id(sum))2 Trong đoạn mã trên, bạn đã gán giá trị Output:
2037008656
2037008688
66 cho Output:
2037008656
2037008688
67. Nếu bạn cố sửa đổi giá trị này bằng phép cộng, thì bạn sẽ nhận được một đối tượng mới>>> def sum(var1,var2): return var1+var2 print("Address of funtion sum: ",id(sum))5 Mặc dù đoạn mã trên dường như sửa đổi giá trị của Output:
2037008656
2037008688
67, bạn vẫn nhận được một đối tượng mới làm phản hồiLoại 9 cũng không thay đổi>>> def sum(var1,var2): return var1+var2 print("Address of funtion sum: ",id(sum))8 Một lần nữa, def sum(var1,var2): return var1+var2 print("Address of funtion sum: ",id(sum))90 kết thúc với một địa chỉ bộ nhớ khác sau thao tác def sum(var1,var2): return var1+var2 print("Address of funtion sum: ",id(sum))91 Thưởng. Toán tử def sum(var1,var2): return var1+var2 print("Address of funtion sum: ",id(sum))91 dịch sang các lệnh gọi phương thức khác nhau Đối với một số đối tượng như Output:
2037008656
2037008688
60, thì def sum(var1,var2): return var1+var2 print("Address of funtion sum: ",id(sum))91 sẽ chuyển thành def sum(var1,var2): return var1+var2 print("Address of funtion sum: ",id(sum))95 (thêm tại chỗ). Điều này sẽ sửa đổi def sum(var1,var2): return var1+var2 print("Address of funtion sum: ",id(sum))96 và trả về cùng một ID. Tuy nhiên, 9 và 3 không có các phương thức này và dẫn đến các cuộc gọi def sum(var1,var2): return var1+var2 print("Address of funtion sum: ",id(sum))99 thay vì def sum(var1,var2): return var1+var2 print("Address of funtion sum: ",id(sum))95 Để biết thêm thông tin chi tiết, hãy xem Python Cố gắng thay đổi trực tiếp chuỗi def sum(var1,var2): return var1+var2 print("Address of funtion sum: ",id(sum))90 dẫn đến lỗi >>>
Đoạn mã trên không thành công và Python chỉ ra rằng 9 không hỗ trợ đột biến này, điều này phù hợp với định nghĩa rằng loại 9 là bất biếnNgược lại với một đối tượng có thể thay đổi, như Output:
2037008656
2037008688
60>>> Output:
2037008656
2037008688
6Mã này cho thấy sự khác biệt lớn trong hai loại đối tượng. var1 = 2.60 print(hex(id(var1))) # print the address of var1 in hexadecimal format var2 = 3.90 print(hex(id(var2))) #print the address of var2 in hexadecimal format str1="Hello" print(hex(id(str1))) #print the address of str1 in hexadecimal format65 ban đầu có id. Ngay cả sau khi var1 = 2.60 print(hex(id(var1))) # print the address of var1 in hexadecimal format var2 = 3.90 print(hex(id(var2))) #print the address of var2 in hexadecimal format str1="Hello" print(hex(id(str1))) #print the address of str1 in hexadecimal format66 được thêm vào danh sách, thì var1 = 2.60 print(hex(id(var1))) # print the address of var1 in hexadecimal format var2 = 3.90 print(hex(id(var2))) #print the address of var2 in hexadecimal format str1="Hello" print(hex(id(str1))) #print the address of str1 in hexadecimal format65 vẫn có cùng một id. Điều này là do loại Output:
2037008656
2037008688
60 có thể thay đổiMột cách khác để chứng minh rằng danh sách có thể thay đổi được là gán >>> def sum(var1,var2): return var1+var2 print("Address of funtion sum: ",id(sum))9 Trong mã này, bạn biến đổi var1 = 2.60 print(hex(id(var1))) # print the address of var1 in hexadecimal format var2 = 3.90 print(hex(id(var2))) #print the address of var2 in hexadecimal format str1="Hello" print(hex(id(str1))) #print the address of str1 in hexadecimal format65 và đặt phần tử đầu tiên của nó thành Output: '0x353a208' '0x3500588' '0x352f180'20. Tuy nhiên, nó vẫn duy trì cùng một id ngay cả sau khi chuyển nhượng này. Với các đối tượng có thể thay đổi và không thể thay đổi, bước tiếp theo trong hành trình của bạn là tìm hiểu hệ sinh thái có thể thay đổi của PythonLoại bỏ các quảng cáo Hiểu các biếnCác biến trong Python về cơ bản khác với các biến trong C hoặc C++. Trên thực tế, Python thậm chí không có biến. Python có tên, không phải biến Điều này có vẻ khoa trương, và phần lớn, nó là. Hầu hết thời gian, bạn hoàn toàn có thể coi tên Python là biến, nhưng hiểu được sự khác biệt là rất quan trọng. Điều này đặc biệt đúng khi bạn đang điều hướng chủ đề phức tạp của con trỏ trong Python Để giúp hiểu rõ sự khác biệt, bạn có thể xem cách các biến hoạt động trong C, chúng đại diện cho cái gì và sau đó đối chiếu điều đó với cách các tên hoạt động trong Python Biến trong CGiả sử bạn có đoạn mã sau xác định biến Output:
2037008656
2037008688
67var1 = 2.60 print(hex(id(var1))) # print the address of var1 in hexadecimal format var2 = 3.90 print(hex(id(var2))) #print the address of var2 in hexadecimal format str1="Hello" print(hex(id(str1))) #print the address of str1 in hexadecimal format6 Một dòng mã này có một số bước riêng biệt khi được thực thi
Được hiển thị trong chế độ xem đơn giản hóa của bộ nhớ, nó có thể trông như thế này Ở đây, bạn có thể thấy rằng biến Output:
2037008656
2037008688
67 có vị trí bộ nhớ giả mạo là Output: '0x353a208' '0x3500588' '0x352f180'25 và giá trị Output: '0x353a208' '0x3500588' '0x352f180'22. Nếu sau này trong chương trình, bạn muốn thay đổi giá trị của Output:
2037008656
2037008688
67, bạn có thể làm như sauOutput: '0x353a208' '0x3500588' '0x352f180'2 Đoạn mã trên gán một giá trị mới ( Output: '0x353a208' '0x3500588' '0x352f180'28) cho biến Output:
2037008656
2037008688
67, do đó ghi đè lên giá trị trước đó. Điều này có nghĩa là biến Output:
2037008656
2037008688
67 có thể thay đổi. Bố cục bộ nhớ được cập nhật hiển thị giá trị mớiLưu ý rằng vị trí của Output:
2037008656
2037008688
67 không thay đổi, chỉ có giá trị. Đây là một điểm đáng kể. Điều đó có nghĩa là Output:
2037008656
2037008688
67 là vị trí bộ nhớ, không chỉ là tên cho nóMột cách khác để nghĩ về khái niệm này là về quyền sở hữu. Theo một nghĩa nào đó, Output:
2037008656
2037008688
67 sở hữu vị trí bộ nhớ. Ban đầu, Output:
2037008656
2037008688
67 là một hộp trống có thể chứa chính xác một số nguyên trong đó các giá trị số nguyên có thể được lưu trữKhi bạn gán một giá trị cho Output:
2037008656
2037008688
67, bạn đang đặt một giá trị vào ô mà Output:
2037008656
2037008688
67 sở hữu. Nếu bạn muốn giới thiệu một biến mới ( 17), bạn có thể thêm dòng mã này 1Mã này tạo một hộp mới có tên là 17 và sao chép giá trị từ Output:
2037008656
2037008688
67 vào hộp. Bây giờ bố cục bộ nhớ sẽ như thế nàyThông báo vị trí mới def sum(var1,var2): return var1+var2 print("Address of funtion sum: ",id(sum))200 của 17. Mặc dù giá trị của Output:
2037008656
2037008688
67 đã được sao chép sang 17, biến 17 sở hữu một số địa chỉ mới trong bộ nhớ. Do đó, bạn có thể ghi đè lên giá trị của 17 mà không ảnh hưởng đến Output:
2037008656
2037008688
67def sum(var1,var2): return var1+var2 print("Address of funtion sum: ",id(sum))20 Bây giờ bố cục bộ nhớ sẽ như thế này Một lần nữa, bạn đã sửa đổi giá trị tại 17, nhưng không sửa đổi vị trí của nó. Ngoài ra, bạn hoàn toàn không ảnh hưởng đến biến Output:
2037008656
2037008688
67 ban đầu. Điều này hoàn toàn trái ngược với cách hoạt động của tên PythonLoại bỏ các quảng cáoTên trong PythonPython không có biến. Nó có tên. Vâng, đây là một điểm mô phạm và bạn chắc chắn có thể sử dụng thuật ngữ biến bao nhiêu tùy thích. Điều quan trọng cần biết là có sự khác biệt giữa các biến và tên Hãy lấy mã tương đương từ ví dụ C ở trên và viết nó bằng Python >>> def sum(var1,var2): return var1+var2 print("Address of funtion sum: ",id(sum))21 Giống như trong C, đoạn mã trên được chia thành nhiều bước riêng biệt trong quá trình thực thi
Ghi chú. Điều này không giống với def sum(var1,var2): return var1+var2 print("Address of funtion sum: ",id(sum))218 của Python. Nó dành riêng cho CPython và đại diện cho cấu trúc cơ sở cho tất cả các đối tượng Python def sum(var1,var2): return var1+var2 print("Address of funtion sum: ",id(sum))209 được định nghĩa là một cấu trúc C, vì vậy nếu bạn đang thắc mắc tại sao bạn không thể gọi trực tiếp def sum(var1,var2): return var1+var2 print("Address of funtion sum: ",id(sum))220 hoặc def sum(var1,var2): return var1+var2 print("Address of funtion sum: ",id(sum))221, thì đó là vì bạn không có quyền truy cập trực tiếp vào cấu trúc. Các cuộc gọi phương thức như có thể giúp nhận được một số nội bộ Trong bộ nhớ, nó có thể trông giống như thế này Bạn có thể thấy rằng cách bố trí bộ nhớ khác rất nhiều so với cách bố trí C trước đây. Thay vì Output:
2037008656
2037008688
67 sở hữu khối bộ nhớ chứa giá trị Output: '0x353a208' '0x3500588' '0x352f180'22, đối tượng Python mới được tạo sẽ sở hữu bộ nhớ chứa Output: '0x353a208' '0x3500588' '0x352f180'22. Tên Python Output:
2037008656
2037008688
67 không sở hữu trực tiếp bất kỳ địa chỉ bộ nhớ nào theo cách mà biến C Output:
2037008656
2037008688
67 sở hữu một vị trí tĩnh trong bộ nhớNếu bạn định gán một giá trị mới cho Output:
2037008656
2037008688
67, bạn có thể thử cách sau>>> def sum(var1,var2): return var1+var2 print("Address of funtion sum: ",id(sum))22 Những gì đang xảy ra ở đây khác với tương đương với C, nhưng không quá khác so với ràng buộc ban đầu trong Python mã này
Bây giờ trong bộ nhớ, nó sẽ giống như thế này Sơ đồ này giúp minh họa rằng Output:
2037008656
2037008688
67 trỏ đến một tham chiếu đến một đối tượng và không sở hữu không gian bộ nhớ như trước đây. Nó cũng chỉ ra rằng lệnh def sum(var1,var2): return var1+var2 print("Address of funtion sum: ",id(sum))238 không phải là một phép gán, mà là ràng buộc tên Output:
2037008656
2037008688
67 với một tham chiếuNgoài ra, đối tượng trước đó (giữ giá trị Output: '0x353a208' '0x3500588' '0x352f180'22) hiện đang nằm trong bộ nhớ với số tham chiếu là 0 và sẽ được dọn sạch bởi Bạn có thể giới thiệu một tên mới, 17, cho hỗn hợp như trong ví dụ C>>> def sum(var1,var2): return var1+var2 print("Address of funtion sum: ",id(sum))23 Trong bộ nhớ, bạn sẽ có một tên mới, nhưng không nhất thiết phải là một đối tượng mới Bây giờ bạn có thể thấy rằng một đối tượng Python mới chưa được tạo, chỉ có một tên mới trỏ đến cùng một đối tượng. Ngoài ra, số lượt truy cập của đối tượng đã tăng thêm một. Bạn có thể kiểm tra sự bình đẳng nhận dạng đối tượng để xác nhận rằng chúng giống nhau >>> def sum(var1,var2): return var1+var2 print("Address of funtion sum: ",id(sum))24 Đoạn mã trên chỉ ra rằng Output:
2037008656
2037008688
67 và 17 là cùng một đối tượng. mặc dù không phạm sai lầm. 17 vẫn bất biếnVí dụ: bạn có thể thực hiện phép cộng trên 17>>> def sum(var1,var2): return var1+var2 print("Address of funtion sum: ",id(sum))25 Sau lệnh gọi bổ sung, bạn được trả về một đối tượng Python mới. Bây giờ, bộ nhớ trông như thế này Một đối tượng mới đã được tạo và 17 hiện trỏ đến đối tượng mới. Thật thú vị, đây là trạng thái kết thúc tương tự nếu bạn đã ràng buộc trực tiếp 17 với def sum(var1,var2): return var1+var2 print("Address of funtion sum: ",id(sum))248 >>> def sum(var1,var2): return var1+var2 print("Address of funtion sum: ",id(sum))26 Câu lệnh trên dẫn đến trạng thái bộ nhớ cuối giống như phần bổ sung. Tóm lại, trong Python, bạn không gán biến. Thay vào đó, bạn liên kết tên với tài liệu tham khảo Loại bỏ các quảng cáoLưu ý về các đối tượng thực tập trong PythonBây giờ bạn đã hiểu cách các đối tượng Python được tạo và các tên được liên kết với các đối tượng đó, đã đến lúc bắt tay vào thực hiện. Cờ lê đó đi theo tên của các đối tượng được thực tập Giả sử bạn có mã Python sau >>> def sum(var1,var2): return var1+var2 print("Address of funtion sum: ",id(sum))27 Như trên, Output:
2037008656
2037008688
67 và 17 đều là tên trỏ đến cùng một đối tượng Python. Nhưng đối tượng Python chứa giá trị def sum(var1,var2): return var1+var2 print("Address of funtion sum: ",id(sum))251 không phải lúc nào cũng đảm bảo có cùng địa chỉ bộ nhớ. Ví dụ: nếu bạn cộng hai số lại với nhau để có được def sum(var1,var2): return var1+var2 print("Address of funtion sum: ",id(sum))251, bạn sẽ nhận được một địa chỉ bộ nhớ khác >>> def sum(var1,var2): return var1+var2 print("Address of funtion sum: ",id(sum))28 Lần này, dòng def sum(var1,var2): return var1+var2 print("Address of funtion sum: ",id(sum))253 trả về def sum(var1,var2): return var1+var2 print("Address of funtion sum: ",id(sum))254. Nếu điều này gây nhầm lẫn, thì đừng lo lắng. Dưới đây là các bước xảy ra khi mã này được thực thi
Lưu ý kỹ thuật. Các bước trên chỉ xảy ra khi mã này được thực thi bên trong REPL. Nếu bạn lấy ví dụ trên, dán nó vào một tệp và chạy tệp đó, thì bạn sẽ thấy rằng dòng def sum(var1,var2): return var1+var2 print("Address of funtion sum: ",id(sum))253 sẽ trả về Output:
2037008656
2037008688
65Điều này xảy ra bởi vì trình biên dịch thông minh. Trình biên dịch CPython cố gắng thực hiện các tối ưu hóa được gọi là tối ưu hóa lỗ nhìn trộm, giúp lưu các bước thực hiện bất cứ khi nào có thể. Để biết thông tin chi tiết, bạn có thể xem mã nguồn trình tối ưu hóa lỗ nhìn trộm của CPython Đây không phải là lãng phí sao? . Bạn không bao giờ phải lo lắng về việc dọn dẹp các đối tượng trung gian này hoặc thậm chí không cần biết rằng chúng tồn tại. Điều thú vị là các thao tác này tương đối nhanh và bạn chưa bao giờ phải biết bất kỳ chi tiết nào trong số đó cho đến bây giờ Các nhà phát triển cốt lõi của Python, theo sự khôn ngoan của họ, cũng nhận thấy sự lãng phí này và quyết định thực hiện một số tối ưu hóa. Những tối ưu hóa này dẫn đến hành vi có thể gây ngạc nhiên cho người mới >>> def sum(var1,var2): return var1+var2 print("Address of funtion sum: ",id(sum))29 Trong ví dụ này, bạn thấy mã gần giống như trước, ngoại trừ lần này kết quả là Output:
2037008656
2037008688
65. Đây là kết quả của các đối tượng được thực tập. Python tạo trước một tập hợp con nhất định các đối tượng trong bộ nhớ và giữ chúng trong không gian tên chung để sử dụng hàng ngàyĐối tượng nào phụ thuộc vào việc triển khai Python. Trăn 3. 7 thực tập sinh sau
Lý do đằng sau điều này là các biến này rất có khả năng được sử dụng trong nhiều chương trình. Bằng cách thực tập các đối tượng này, Python ngăn các cuộc gọi cấp phát bộ nhớ cho các đối tượng được sử dụng nhất quán Các chuỗi có ít hơn 20 ký tự và chứa các chữ cái, chữ số hoặc dấu gạch dưới ASCII sẽ được thực tập. Lý do đằng sau điều này là chúng được coi là một loại danh tính nào đó >>> def sum(var1,var2): return var1+var2 print("Address of funtion sum: ",id(sum))50 Ở đây bạn có thể thấy rằng cả def sum(var1,var2): return var1+var2 print("Address of funtion sum: ",id(sum))266 và def sum(var1,var2): return var1+var2 print("Address of funtion sum: ",id(sum))267 đều trỏ đến cùng một địa chỉ trong bộ nhớ. Nếu bạn nhập một chữ cái, chữ số hoặc dấu gạch dưới không phải ASCII, thì bạn sẽ nhận được một kết quả khác >>> def sum(var1,var2): return var1+var2 print("Address of funtion sum: ",id(sum))51 Bởi vì ví dụ này có dấu chấm than ( def sum(var1,var2): return var1+var2 print("Address of funtion sum: ",id(sum))268) trong đó, các chuỗi này không được thực hiện và là các đối tượng khác nhau trong bộ nhớ Thưởng. Nếu bạn thực sự muốn các đối tượng này tham chiếu cùng một đối tượng bên trong, thì bạn có thể muốn xem def sum(var1,var2): return var1+var2 print("Address of funtion sum: ",id(sum))269. Một trong những trường hợp sử dụng cho chức năng này được nêu trong tài liệu
Các đối tượng được thực tập thường là một nguồn gây nhầm lẫn. Chỉ cần nhớ rằng, nếu bạn còn nghi ngờ, bạn luôn có thể sử dụng Output:
2037008656
2037008688
63 và Output:
2037008656
2037008688
64 để xác định đẳng thức đối tượngLoại bỏ các quảng cáoMô phỏng con trỏ trong PythonChỉ vì con trỏ trong Python không tồn tại tự nhiên không có nghĩa là bạn không thể nhận được lợi ích của việc sử dụng con trỏ. Trên thực tế, có nhiều cách để mô phỏng con trỏ trong Python. Bạn sẽ học được hai trong phần này
Được rồi, chúng ta hãy đi thẳng vào vấn đề Sử dụng các loại có thể thay đổi làm con trỏBạn đã học về các loại có thể thay đổi. Bởi vì những đối tượng này có thể thay đổi, bạn có thể coi chúng như thể chúng là con trỏ để mô phỏng hành vi của con trỏ. Giả sử bạn muốn sao chép mã c sau def sum(var1,var2): return var1+var2 print("Address of funtion sum: ",id(sum))52 Mã này lấy một con trỏ tới một số nguyên ( def sum(var1,var2): return var1+var2 print("Address of funtion sum: ",id(sum))272) và sau đó tăng giá trị lên một. Đây là một chức năng chính để thực hiện mã def sum(var1,var2): return var1+var2 print("Address of funtion sum: ",id(sum))53 Trong đoạn mã trên, bạn gán Output: '0x353a208' '0x3500588' '0x352f180'22 cho 17, in ra giá trị hiện tại, tăng giá trị lên một rồi in ra giá trị đã sửa đổi. Đầu ra của việc thực thi mã này sẽ như saudef sum(var1,var2): return var1+var2 print("Address of funtion sum: ",id(sum))54 Một cách để sao chép loại hành vi này trong Python là sử dụng loại có thể thay đổi. Cân nhắc sử dụng danh sách và sửa đổi phần tử đầu tiên >>> def sum(var1,var2): return var1+var2 print("Address of funtion sum: ",id(sum))55 Ở đây, def sum(var1,var2): return var1+var2 print("Address of funtion sum: ",id(sum))275 truy cập phần tử đầu tiên và tăng giá trị của nó lên một. Sử dụng Output:
2037008656
2037008688
60 có nghĩa là kết quả cuối cùng dường như đã sửa đổi giá trị. Vậy con trỏ trong Python có tồn tại không? . Điều này chỉ khả thi vì Output:
2037008656
2037008688
60 là loại có thể thay đổi. Nếu bạn cố sử dụng 7, bạn sẽ gặp lỗi>>> def sum(var1,var2): return var1+var2 print("Address of funtion sum: ",id(sum))56 Đoạn mã trên chứng minh rằng 7 là bất biến. Do đó, nó không hỗ trợ gán mục. Output:
2037008656
2037008688
60 không phải là loại có thể thay đổi duy nhất. Một cách phổ biến khác để bắt chước con trỏ trong Python là sử dụng một Output:
2037008656
2037008688
62Giả sử bạn có một ứng dụng mà bạn muốn theo dõi mỗi khi một sự kiện thú vị xảy ra. Một cách để đạt được điều này là tạo một Output:
2037008656
2037008688
62 và sử dụng một trong các mục làm bộ đếm>>> def sum(var1,var2): return var1+var2 print("Address of funtion sum: ",id(sum))57 Trong ví dụ này, từ điển def sum(var1,var2): return var1+var2 print("Address of funtion sum: ",id(sum))283 được sử dụng để theo dõi số lần gọi hàm. Sau khi bạn gọi def sum(var1,var2): return var1+var2 print("Address of funtion sum: ",id(sum))284, bộ đếm đã tăng lên thành def sum(var1,var2): return var1+var2 print("Address of funtion sum: ",id(sum))285 như mong đợi. Tất cả chỉ vì Output:
2037008656
2037008688
62 có thể thay đổiHãy ghi nhớ, điều này chỉ mô phỏng hành vi của con trỏ và không ánh xạ trực tiếp tới con trỏ thực trong C hoặc C++. Điều đó có nghĩa là, các hoạt động này đắt hơn so với trong C hoặc C++ Loại bỏ các quảng cáoSử dụng đối tượng PythonTùy chọn Output:
2037008656
2037008688
62 là một cách tuyệt vời để mô phỏng con trỏ trong Python, nhưng đôi khi việc nhớ tên khóa bạn đã sử dụng trở nên tẻ nhạt. Điều này đặc biệt đúng nếu bạn đang sử dụng từ điển trong các phần khác nhau của ứng dụng của mình. Đây là nơi một lớp Python tùy chỉnh thực sự có thể giúp íchĐể xây dựng trên ví dụ cuối cùng, giả sử rằng bạn muốn theo dõi số liệu trong ứng dụng của mình. Tạo một lớp là một cách tuyệt vời để trừu tượng hóa các chi tiết phiền phức def sum(var1,var2): return var1+var2 print("Address of funtion sum: ",id(sum))58 Mã này định nghĩa một lớp def sum(var1,var2): return var1+var2 print("Address of funtion sum: ",id(sum))288. Lớp này vẫn sử dụng một Output:
2037008656
2037008688
62 để giữ dữ liệu thực, nằm trong biến thành viên def sum(var1,var2): return var1+var2 print("Address of funtion sum: ",id(sum))290. Điều này sẽ cung cấp cho bạn khả năng thay đổi mà bạn cần. Bây giờ bạn chỉ cần có thể truy cập các giá trị này. Một cách hay để làm điều này là với các thuộc tính def sum(var1,var2): return var1+var2 print("Address of funtion sum: ",id(sum))59 Mã này sử dụng. Nếu bạn không quen thuộc với các công cụ trang trí, bạn có thể xem qua Primer on Python Decorators này. Trình trang trí def sum(var1,var2): return var1+var2 print("Address of funtion sum: ",id(sum))291 ở đây cho phép bạn truy cập def sum(var1,var2): return var1+var2 print("Address of funtion sum: ",id(sum))293 và def sum(var1,var2): return var1+var2 print("Address of funtion sum: ",id(sum))294 như thể chúng là các thuộc tính >>> def sum(var1,var2): return var1+var2 print("Address of funtion sum: ",id(sum))80 Việc bạn có thể truy cập những tên này dưới dạng thuộc tính có nghĩa là bạn đã trừu tượng hóa thực tế rằng những giá trị này nằm trong một Output:
2037008656
2037008688
62. Bạn cũng nói rõ hơn tên của các thuộc tính là gì. Tất nhiên, bạn cần có khả năng tăng các giá trị nàydef sum(var1,var2): return var1+var2 print("Address of funtion sum: ",id(sum))81 Bạn đã giới thiệu hai phương pháp mới
Các phương pháp này sửa đổi các giá trị trong số liệu Output:
2037008656
2037008688
62. Bây giờ bạn có một lớp mà bạn sửa đổi như thể bạn đang sửa đổi một con trỏ>>> def sum(var1,var2): return var1+var2 print("Address of funtion sum: ",id(sum))82 Tại đây, bạn có thể truy cập ________ 2293 và gọi ________ 2296 ở nhiều vị trí khác nhau trong ứng dụng của mình và mô phỏng con trỏ trong Python. Điều này hữu ích khi bạn có thứ gì đó như số liệu cần được sử dụng và cập nhật thường xuyên trong các phần khác nhau của ứng dụng của bạn Ghi chú. Đặc biệt, trong lớp này, việc đặt rõ ràng def sum(var1,var2): return var1+var2 print("Address of funtion sum: ",id(sum))296 và def sum(var1,var2): return var1+var2 print("Address of funtion sum: ",id(sum))297 thay vì sử dụng def sum(var1,var2): return var1+var2 print("Address of funtion sum: ",id(sum))503 sẽ ngăn người dùng đặt các giá trị này thành một giá trị 3 tùy ý hoặc một giá trị không hợp lệ như Output:
2037008656
2037008688
62Đây là nguồn đầy đủ cho lớp def sum(var1,var2): return var1+var2 print("Address of funtion sum: ",id(sum))288 def sum(var1,var2): return var1+var2 print("Address of funtion sum: ",id(sum))83 Con trỏ thực với >>> s[0] = "R"
Traceback (most recent call last):
File " |