Mỗi biến có một vị trí bộ nhớ tương ứng và mỗi vị trí bộ nhớ có một địa chỉ tương ứng được xác định cho nó. Con trỏ lưu trữ địa chỉ của các biến khác
Đáng ngạc nhiên là con trỏ không thực sự tồn tại trong Python. Nếu đó là trường hợp, những gì tôi đang viết ở đây?
Mọi thứ đều là đối tượng trong Python. Trong bài viết này, chúng ta sẽ xem xét mô hình đối tượng của Python và xem cách chúng ta có thể giả mạo con trỏ trong Python
Mục lụcBạn có thể bỏ qua bất kỳ phần cụ thể nào của hướng dẫn con trỏ Python này bằng cách sử dụng mục lục bên dưới
Không ai biết tại sao con trỏ không tồn tại trong Python
Bạn đã đọc đúng
lý do là không rõ
Ngay cả trong các ngôn ngữ lập trình cơ bản như C và C++, con trỏ được coi là phức tạp
Sự phức tạp này đi ngược lại Zen của Python và đây có thể là lý do tại sao Python không nói về lý do tại sao nó không bao gồm các con trỏ
Nói cách khác, mục tiêu của Python là giữ mọi thứ đơn giản. Con trỏ không được coi là đơn giản
Mặc dù khái niệm về con trỏ là xa lạ với Python, nhưng mục tiêu tương tự có thể được đáp ứng với sự trợ giúp của các đối tượng. Trước khi thảo luận thêm về vấn đề này, trước tiên chúng ta hãy hiểu vai trò của các đối tượng trong Python
Đối tượng là gì?
Mọi thứ đều là đối tượng trong Python
Nếu bạn mới bắt đầu với Python, hãy sử dụng bất kỳ REPL nào và khám phá phương pháp
94169658712768
7 để hiểu điều nàyCụ thể hơn, đoạn mã sau chứng minh rằng các kiểu dữ liệu
94169658712768
8, 94169658712768
9, x = y
x is y
0 và x = y
x is y
1 là từng đối tượng trong Pythonprint[isinstance[int, object]]
print[isinstance[str, object]]
print[isinstance[list, object]]
print[isinstance[bool, object]]
đầu ra
True
True
True
True
Điều này chứng tỏ mọi thứ trong Python đều là đối tượng
Vậy đối tượng là gì?
Một đối tượng Python bao gồm ba phần
- số tham chiếu
- Loại
- Giá trị
Số lượng tham chiếu là số lượng biến tham chiếu đến một vị trí bộ nhớ cụ thể
Loại đề cập đến loại đối tượng. Ví dụ về các loại Python bao gồm
94169658712768
8, x = y
x is y
3, x = y
x is y
4 và x = y
x is y
5Giá trị là giá trị thực của đối tượng được lưu trữ trong bộ nhớ
Các đối tượng trong Python có hai loại - Bất biến và Có thể thay đổi
Điều quan trọng là phải hiểu sự khác biệt giữa các đối tượng không thay đổi và có thể thay đổi để triển khai hành vi con trỏ trong Python
Trước tiên hãy phân tách các loại dữ liệu trong Python thành các đối tượng không thể thay đổi và có thể thay đổi
ImmutableMutableintlistfloatsetstrdictboolcomplextupleFrozenset{. blueTable}
Các đối tượng bất biến không thể thay đổi bài tạo. Trong bảng trên, bạn có thể thấy các kiểu dữ liệu thường được sử dụng trong Python đều là các đối tượng bất biến. Hãy xem ví dụ dưới đây
x = 34
y = id[x]
print[y]
Khi bạn chạy tập lệnh này trong môi trường REPL của mình, bạn sẽ nhận được địa chỉ bộ nhớ có giá trị
đầu ra
94562650443584
Bây giờ, hãy thay đổi giá trị của x và xem điều gì sẽ xảy ra. Giá trị của x trong bộ nhớ 94562650443584 là 34 và không thể thay đổi. Nếu chúng ta thay đổi giá trị của x, nó sẽ tạo ra một đối tượng mới
x = 34
y = id[x]
print[y]
x += 1
y= id[x]
print[y]
đầu ra
94169658712736
94169658712768
Sử dụng is[] để xác minh xem hai đối tượng có chia sẻ cùng một địa chỉ bộ nhớ không. Hãy xem một ví dụ
x = y
x is y
Nếu đầu ra là true, nó chỉ ra rằng x và y chia sẻ cùng một địa chỉ bộ nhớ
Các đối tượng có thể thay đổi có thể được chỉnh sửa ngay cả sau khi tạo. Không giống như trong các đối tượng bất biến, không có đối tượng mới nào được tạo khi một đối tượng có thể thay đổi được sửa đổi. Hãy sử dụng đối tượng danh sách là đối tượng có thể thay đổi
numbs = [1, 1, 2, 3, 5]
print["---------Before Modification------------"]
print[id[numbs]]
print[]
## element modification
numbs[0] += 1
print["-----------After Element Modification-------------"]
print[id[numbs]]
print[]
đầu ra
---------Before Modification------------
140469873815424
True
True
True
True
0Lưu ý rằng địa chỉ của đối tượng vẫn giữ nguyên ngay cả sau khi thực hiện thao tác trên danh sách
Điều này xảy ra vì danh sách là một đối tượng có thể thay đổi. Khái niệm tương tự áp dụng cho các đối tượng có thể thay đổi khác như
x = y
x is y
6 hoặc x = y
x is y
7 được đề cập trong bảng được trình bày trước đó trong hướng dẫn nàyBây giờ chúng ta đã hiểu sự khác biệt giữa các đối tượng có thể thay đổi và không thể thay đổi, chúng ta hãy xem mô hình đối tượng của Python
Biến trong C so với Biến trong PythonCác biến trong Python rất khác so với các biến trong C hoặc C++
Cụ thể hơn, Python không có biến. Thay vào đó, chúng được gọi bằng tên. Để hiểu các biến trong Python khác với biến trong các ngôn ngữ lập trình cơ bản như C và C++ như thế nào, hãy xem một ví dụ
Đầu tiên, hãy định nghĩa một biến trong C
True
True
True
True
1Đoạn mã trên thực sự làm gì?
Dòng mã này
- Cấp phát bộ nhớ cho kiểu dữ liệu đã xác định, trong trường hợp này là
894169658712768
- Phân bổ một giá trị
9 cho vị trí bộ nhớ, chẳng hạn nhưx = y x is y
0numbs = [1, 1, 2, 3, 5] print["---------Before Modification------------"] print[id[numbs]] print[] ## element modification numbs[0] += 1 print["-----------After Element Modification-------------"] print[id[numbs]] print[]
- Cho biết biến
1 nhận giá trịnumbs = [1, 1, 2, 3, 5] print["---------Before Modification------------"] print[id[numbs]] print[] ## element modification numbs[0] += 1 print["-----------After Element Modification-------------"] print[id[numbs]] print[]
9x = y x is y
Trong C, nếu bạn muốn thay đổi giá trị của v sau đó, bạn có thể làm điều này
True
True
True
True
2Bây giờ, giá trị 20 được phân bổ cho vị trí bộ nhớ
numbs = [1, 1, 2, 3, 5]
print["---------Before Modification------------"]
print[id[numbs]]
print[]
## element modification
numbs[0] += 1
print["-----------After Element Modification-------------"]
print[id[numbs]]
print[]
0. Vì biến v là một đối tượng có thể thay đổi nên vị trí của biến không thay đổi mặc dù giá trị của nó thay đổi. Nghĩa là, numbs = [1, 1, 2, 3, 5]
print["---------Before Modification------------"]
print[id[numbs]]
print[]
## element modification
numbs[0] += 1
print["-----------After Element Modification-------------"]
print[id[numbs]]
print[]
1 được xác định ở đây không chỉ là tên của biến mà còn là vị trí bộ nhớ của nóBây giờ, hãy gán giá trị của v cho một biến mới
True
True
True
True
3Một biến mới mới hiện được tạo với giá trị 20 nhưng biến này sẽ có vị trí bộ nhớ riêng và sẽ không lấy vị trí bộ nhớ của biến có giá trị mà nó đã sao chép
Trong Python, tên hoạt động theo cách tương phản với những gì chúng ta vừa thấy
Hãy viết lại Python tương đương với đoạn mã trên để xem nguyên tắc này hoạt động
True
True
True
True
4Dòng mã này
- Tạo một đối tượng Python mới
- Đặt kiểu dữ liệu cho đối tượng Python là số nguyên
- Gán giá trị 10 cho PyObject
- Tạo tên
1numbs = [1, 1, 2, 3, 5] print["---------Before Modification------------"] print[id[numbs]] print[] ## element modification numbs[0] += 1 print["-----------After Element Modification-------------"] print[id[numbs]] print[]
- Điểm
1 cho PyObject mới được tạonumbs = [1, 1, 2, 3, 5] print["---------Before Modification------------"] print[id[numbs]] print[] ## element modification numbs[0] += 1 print["-----------After Element Modification-------------"] print[id[numbs]] print[]
- Tăng số lượt truy cập của đối tượng Python mới được tạo lên 1
Hãy hình dung và làm cho sự hiểu biết của chúng tôi đơn giản
Không giống như trong C, một đối tượng mới được tạo và các đối tượng đó sở hữu vị trí bộ nhớ của biến
Tên được xác định là
numbs = [1, 1, 2, 3, 5]
print["---------Before Modification------------"]
print[id[numbs]]
print[]
## element modification
numbs[0] += 1
print["-----------After Element Modification-------------"]
print[id[numbs]]
print[]
1, hiện sở hữu bất kỳ vị trí bộ nhớ nàoBây giờ, hãy gán một giá trị khác cho
numbs = [1, 1, 2, 3, 5]
print["---------Before Modification------------"]
print[id[numbs]]
print[]
## element modification
numbs[0] += 1
print["-----------After Element Modification-------------"]
print[id[numbs]]
print[]
1True
True
True
True
5Hãy xem những gì xảy ra ở đây
- Đầu tiên, điều này tạo ra một PyObject mới
- Đặt kiểu dữ liệu cho PyObject là số nguyên
- Gán giá trị 20 cho PyObject
- Điểm v tới PyObject mới được tạo
- Tăng số lượng truy cập của PyObject mới được tạo lên 1
- Giảm refcount của PyObject đã tồn tại xuống 1
Tên biến
numbs = [1, 1, 2, 3, 5]
print["---------Before Modification------------"]
print[id[numbs]]
print[]
## element modification
numbs[0] += 1
print["-----------After Element Modification-------------"]
print[id[numbs]]
print[]
1 bây giờ trỏ đến đối tượng mới được tạo. Đối tượng đầu tiên có giá trị x = y
x is y
9 hiện có số lượng truy cập bằng 0. Điều này sẽ được làm sạch bởi bộ thu gom rácBây giờ hãy gán giá trị của
numbs = [1, 1, 2, 3, 5]
print["---------Before Modification------------"]
print[id[numbs]]
print[]
## element modification
numbs[0] += 1
print["-----------After Element Modification-------------"]
print[id[numbs]]
print[]
1 cho một biến mớiTrue
True
True
True
6Trong Python, điều này tạo ra một tên mới chứ không phải một đối tượng mới
Bạn có thể xác thực điều này bằng cách sử dụng tập lệnh bên dưới
True
True
True
True
7Đầu ra sẽ đúng. Lưu ý rằng
---------Before Modification------------
140469873815424
2 vẫn là một đối tượng bất biến. Bạn có thể thực hiện bất kỳ thao tác nào trên ---------Before Modification------------
140469873815424
2 và nó sẽ tạo một đối tượng mớiHành vi con trỏ trong PythonBây giờ chúng ta đã hiểu rõ về các đối tượng có thể thay đổi là gì, hãy xem cách chúng ta có thể sử dụng hành vi của đối tượng này để mô phỏng các con trỏ trong Python. Chúng tôi cũng sẽ thảo luận về cách chúng tôi có thể sử dụng các đối tượng Python tùy chỉnh
Sử dụng đối tượng có thể thay đổi
Chúng ta có thể coi các đối tượng có thể thay đổi như con trỏ. Hãy xem cách sao chép mã C bên dưới bằng Python
True
True
True
True
8Trong đoạn mã trên,
numbs = [1, 1, 2, 3, 5]
print["---------Before Modification------------"]
print[id[numbs]]
print[]
## element modification
numbs[0] += 1
print["-----------After Element Modification-------------"]
print[id[numbs]]
print[]
1 được gán với giá trị x = y
x is y
9. Giá trị hiện tại được in và sau đó giá trị của numbs = [1, 1, 2, 3, 5]
print["---------Before Modification------------"]
print[id[numbs]]
print[]
## element modification
numbs[0] += 1
print["-----------After Element Modification-------------"]
print[id[numbs]]
print[]
1 được tăng lên 10 trước khi in giá trị mới. Đầu ra của mã này sẽ làTrue
True
True
True
9Hãy sao chép hành vi này trong Python bằng cách sử dụng một đối tượng có thể thay đổi. Chúng tôi sẽ sử dụng một danh sách và sửa đổi phần tử đầu tiên của danh sách
x = 34
y = id[x]
print[y]
0đầu ra
x = 34
y = id[x]
print[y]
1Ở đây,
---------Before Modification------------
140469873815424
7 tăng giá trị phần tử đầu tiên lên một. Vì vậy, điều này có nghĩa là con trỏ có trong Python? . Điều này là có thể bởi vì chúng tôi đã sử dụng một loại có thể thay đổi, danh sách. Hãy thử cùng một mã bằng cách sử dụng tuple. Bạn sẽ nhận được một lỗix = 34
y = id[x]
print[y]
2đầu ra
x = 34
y = id[x]
print[y]
3Điều này là do tuple là một loại bất biến. Hãy thử sử dụng các đối tượng có thể thay đổi khác để có được đầu ra mong muốn tương tự. Điều quan trọng là phải hiểu rằng chúng ta chỉ giả mạo hành vi của con trỏ bằng cách sử dụng các đối tượng có thể thay đổi
Con trỏ Sử dụng ctypesChúng ta có thể tạo các con trỏ thực trong Python bằng cách sử dụng các mô-đun
---------Before Modification------------
140469873815424
8 tích hợp sẵn. Để bắt đầu, hãy lưu trữ các hàm sử dụng con trỏ trong tệp ---------Before Modification------------
140469873815424
9 và biên dịch nóViết hàm bên dưới vào tệp
---------Before Modification------------
140469873815424
9 của bạnx = 34
y = id[x]
print[y]
4Giả sử tên tệp của chúng tôi là
True
True
True
True
01. Chạy các lệnh dưới đâyx = 34
y = id[x]
print[y]
5Trong lệnh đầu tiên,
True
True
True
True
01 được biên dịch thành một đối tượng True
True
True
True
03. Sau đó, tệp đối tượng này được đưa đến sản xuất_______6_______04 để làm việc với True
True
True
True
05x = 34
y = id[x]
print[y]
6đầu ra
x = 34
y = id[x]
print[y]
7True
True
True
True
06 trả về đối tượng được chia sẻ True
True
True
True
07. Hãy để chúng tôi định nghĩa hàm ---------Before Modification------------
140469873815424
7 trong đối tượng chia sẻ True
True
True
True
09. Chúng ta phải sử dụng ctypes để chuyển một con trỏ tới các hàm được xác định trong một đối tượng được chia sẻx = 34
y = id[x]
print[y]
8Chúng ta sẽ gặp lỗi nếu thử gọi hàm này bằng một kiểu khác
x = 34
y = id[x]
print[y]
9đầu ra
94562650443584
0Lỗi nói rằng một con trỏ được yêu cầu bởi chức năng. Bạn phải sử dụng biến C trong ctypes để chuyển tham chiếu biến
94562650443584
1Ở đây
numbs = [1, 1, 2, 3, 5]
print["---------Before Modification------------"]
print[id[numbs]]
print[]
## element modification
numbs[0] += 1
print["-----------After Element Modification-------------"]
print[id[numbs]]
print[]
1 là biến C và True
True
True
True
11 chuyển tham chiếu biếnđầu ra
94562650443584
2Suy nghĩ cuối cùngNhư chúng ta đã thấy trong hướng dẫn này, hành vi của con trỏ có thể được triển khai trong Python mặc dù về mặt kỹ thuật chúng không có sẵn trong ngôn ngữ Python
Mặc dù chúng tôi đã sử dụng các đối tượng có thể thay đổi để mô phỏng hành vi của con trỏ, nhưng con trỏ ctype là con trỏ thực
Nếu bạn thích bài viết này, hãy nhớ tham gia bản tin Nhà phát triển hàng tháng của tôi, nơi tôi gửi những tin tức mới nhất từ thế giới Python và JavaScript