TLDR: Tên Python hoạt động giống như con trỏ với tự động hủy / tham chiếu nhưng không cho phép hoạt động con trỏ rõ ràng. Các mục tiêu khác thể hiện hướng dẫn, hoạt động tương tự như con trỏ.
Việc triển khai CPython sử dụng loại con trỏPyObject*
dưới mui xe. Như vậy, có thể dịch ngữ nghĩa tên sang các phép toán con trỏ. Chìa khóa là tách tên khỏi các đối tượng thực tế .
Mã Python ví dụ bao gồm cả tên ( i
) và đối tượng ( 5
).
i = 5
j = i
j = 3
Điều này có thể được tạm dịch là mã C với các tên và đối tượng riêng biệt .
int three=3, five=5; // objects
int *i, *j; // names
i = &five; // name `i` refers to position of object `5`
j = i; // name `j` refers to referent of `i`
j = &three; // name `j` refers to position of object `3`
Phần quan trọng là "name-as-pointers" không lưu trữ các đối tượng! Chúng tôi không xác định *i = five
, nhưng i = &five
. Tên và đối tượng tồn tại độc lập với nhau.
Tên chỉ trỏ đến các đối tượng hiện có trong bộ nhớ.
Khi gán từ tên sang tên, không có đối tượng nào được trao đổi! Khi chúng tôi định nghĩa j = i
, điều này tương đương với j = &five
. Không i
và cũng không j
được kết nối với khác.
+- name i -+ -\
\
--> + <five> -+
/ | 5 |
+- name j -+ -/ +----------+
Do đó, việc thay đổi mục tiêu của một tên không ảnh hưởng đến tên kia . Nó chỉ cập nhật những gì mà tên cụ thể trỏ đến.
Python cũng có các loại phần tử giống tên khác : tham chiếu thuộc tính ( i.j
), đăng ký ( i[j]
) và cắt ( i[:j]
). Không giống như tên, chỉ trực tiếp đến các đối tượng, cả ba đều gián tiếp đề cập đến các yếu tố của đối tượng.
Mã ví dụ bao gồm cả tên ( i
) và đăng ký ( i[0]
).
i = [1,2,3]
j = i
i[0] = 5
CPython list
sử dụng một mảng C các PyObject*
con trỏ dưới mui xe. Điều này một lần nữa có thể được tạm dịch là mã C với các tên và đối tượng riêng biệt.
typedef struct{
int *elements[3];
} list; // length 3 `list` type
int one = 1, two = 2, three = 3, five = 5;
list values = {&one, &two, &three}; // objects
list *i, *j; // names
i = &values; // name `i` refers to object `[1, 2, 3]`
j = i; // name `j` refers to referent of `i`
i->elements[0] = &five; // leading element of `i` refers to object `5`
Phần quan trọng là chúng tôi đã không thay đổi bất kỳ tên nào! Chúng tôi đã thay đổi i->elements[0]
, phần tử của một đối tượng mà cả tên của chúng tôi đều trỏ đến.
Giá trị của các đối tượng ghép hiện có có thể được thay đổi.
Khi thay đổi giá trị của một đối tượng thông qua tên, các tên không được thay đổi. Cả hai i
và j
vẫn tham chiếu đến cùng một đối tượng, có giá trị mà chúng ta có thể thay đổi.
+- name i -+ -\
\
--> + <values> -+
/ | elements | --> [1, 2, 3]
+- name j -+ -/ +-----------+
Đối tượng trung gian hoạt động tương tự như một con trỏ ở chỗ chúng ta có thể thay đổi trực tiếp những gì nó trỏ tới và tham chiếu nó từ nhiều tên.