Python là một ngôn ngữ tuyệt vời. Vì tính đơn giản của nó, nhiều người chọn nó làm ngôn ngữ lập trình đầu tiên của họ.
Các lập trình viên có kinh nghiệm cũng sử dụng Python mọi lúc nhờ cộng đồng rộng lớn, các gói phong phú và cú pháp rõ ràng.
Nhưng có một vấn đề dường như gây nhầm lẫn cho những người mới bắt đầu cũng như một số nhà phát triển có kinh nghiệm: các đối tượng Python. Cụ thể, sự khác biệt giữa có thể thay đổi và bất biến các đối tượng.
Trong bài đăng này, chúng ta sẽ đào sâu kiến thức về các đối tượng Python, tìm hiểu sự khác biệt giữa có thể thay đổi và bất biến các đối tượng và xem cách chúng ta có thể sử dụng thông dịch viên để hiểu rõ hơn về cách thức hoạt động của Python.
Chúng tôi sẽ sử dụng các chức năng và từ khóa quan trọng như id
và is
và chúng ta sẽ hiểu sự khác biệt giữa x == y
và x is y
.
Bạn có cho nó? Bắt đầu nào.
Không giống như các ngôn ngữ lập trình khác, nơi ngôn ngữ hỗ trợ các đối tượng, trong Python thực sự mọi thứ là một đối tượng – bao gồm số nguyên, danh sách và thậm chí cả hàm.
Chúng tôi có thể sử dụng thông dịch viên của chúng tôi để xác minh rằng:
>>> isinstance(1, object)
True
>>> isinstance(False, object)
True
def my_func():
return "hello"
>>> isinstance(my_func, object)
True
Python có chức năng tích hợp sẵn, id
, trả về địa chỉ của một đối tượng trong bộ nhớ. Ví dụ:
>>> x = 1
>>> id(x)
1470416816
id(obj)
trả về địa chỉ của obj
trong trí nhớỞ trên, chúng tôi đã tạo một vật bằng tên của x
và gán cho nó giá trị của 1
. Sau đó chúng tôi đã sử dụng id(x)
và phát hiện ra rằng đối tượng này được tìm thấy tại địa chỉ 1470416816
trong trí nhớ.
Điều này cho phép chúng tôi kiểm tra những điều thú vị về Python. Giả sử chúng ta tạo hai biến trong Python – một biến có tên là x
và một người có tên là y
– và gán cho chúng cùng một giá trị. Ví dụ, ở đây:
>>> x = "I love Python!"
>>> y = "I love Python!"
Chúng ta có thể sử dụng toán tử đẳng thức (==
) để xác minh rằng chúng thực sự có cùng giá trị trong mắt Python:
>>> x == y
True
Nhưng đây có phải là cùng một đối tượng trong bộ nhớ không? Về lý thuyết, có thể có hai kịch bản rất khác nhau ở đây.
Theo kịch bản (1)chúng tôi thực sự có hai đối tượng khác nhau, một đối tượng có tên là x
và một tên khác y
điều đó chỉ tình cờ có cùng một giá trị.
Tuy nhiên, cũng có thể xảy ra trường hợp Python thực sự chỉ lưu trữ ở đây một đối tượng, có hai tên tham chiếu đến nó – như thể hiện trong tình huống (2):

Chúng ta có thể sử dụng id
chức năng được giới thiệu ở trên để kiểm tra điều này:
>>> x = "I love Python!"
>>> y = "I love Python!"
>>> x == y
True
>>> id(x)
52889984
>>> id(y)
52889384
Vì vậy, như chúng ta có thể thấy, hành vi của Python phù hợp với tình huống (1) được mô tả ở trên. Mặc dù x == y
trong ví dụ này (có nghĩa là, x
và y
có giống nhau giá trị), chúng là các đối tượng khác nhau trong bộ nhớ. Điều này là do id(x) != id(y)
như chúng ta có thể xác minh rõ ràng:
>>> id(x) == id(y)
False
Có một cách ngắn hơn để so sánh ở trên, đó là sử dụng Python’s is
nhà điều hành. Kiểm tra xem x is y
cũng giống như kiểm tra id(x) == id(y)
có nghĩa là liệu x
và y
là cùng một đối tượng trong bộ nhớ:
>>> x == y
True
>>> id(x) == id(y)
False
>>> x is y
False
Điều này làm sáng tỏ sự khác biệt quan trọng giữa toán tử bình đẳng ==
và toán tử nhận dạng is
.
Như bạn có thể thấy trong ví dụ trên, hoàn toàn có thể có hai tên trong Python (x
và y
) bị ràng buộc với hai đối tượng khác nhau (và do đó, x is y
Là False
), trong đó hai đối tượng này có cùng giá trị (vì vậy x == y
Là True
).
Làm cách nào chúng ta có thể tạo một biến khác trỏ đến cùng một đối tượng x
đang trỏ tới? Chúng ta chỉ có thể sử dụng toán tử gán =
như vậy:
>>> x = "I love Python!"
>>> z = x
Để xác minh rằng chúng thực sự trỏ đến cùng một đối tượng, chúng ta có thể sử dụng is
nhà điều hành:
>>> x is z
True
Tất nhiên, điều này có nghĩa là chúng có cùng địa chỉ trong bộ nhớ, vì chúng ta có thể xác minh rõ ràng bằng cách sử dụng id
:
>>> id(x)
54221824
>>> id(z)
54221824
Và, tất nhiên, chúng có cùng giá trị, vì vậy chúng tôi mong đợi x == z
trở về True
cũng:
>>> x == z
True
Chúng tôi đã nói rằng mọi thứ trong Python đều là đối tượng, nhưng có một sự khác biệt quan trọng giữa các đối tượng. Một số đối tượng là có thể thay đổi trong khi một số là bất biến.
Như tôi đã đề cập trước đây, thực tế này gây nhầm lẫn cho nhiều người mới sử dụng Python, vì vậy chúng tôi sẽ đảm bảo rằng nó rõ ràng.
Đối tượng bất biến trong Python
Đối với một số loại trong Python, một khi chúng tôi đã tạo các phiên bản của các loại đó, chúng sẽ không bao giờ thay đổi. họ đang bất biến.
Ví dụ, int
các đối tượng là bất biến trong Python. Điều gì sẽ xảy ra nếu chúng ta cố gắng thay đổi giá trị của một int
vật?
>>> x = 24601
>>> x
24601
>>> x = 24602
>>> x
24602
Chà, có vẻ như chúng ta đã thay đổi x
thành công. Đây chính xác là nơi nhiều người bị nhầm lẫn. Chính xác những gì đã xảy ra dưới mui xe ở đây? Hãy sử dụng id
để điều tra thêm:
>>> x = 24601
>>> x
24601
>>> id(x)
1470416816
>>> x = 24602
>>> x
24602
>>> id(x)
1470416832
Vì vậy, chúng ta có thể thấy rằng bằng cách gán x = 24602
chúng tôi đã không thay đổi giá trị của đối tượng đó x
đã bị ràng buộc trước đó. Thay vào đó, chúng tôi đã tạo một đối tượng mới và đặt tên x
với nó.
Vì vậy sau khi giao 24601
đến x
bằng cách sử dụng x = 24601
chúng tôi đã có trạng thái sau:

Và sau khi sử dụng x = 24602
chúng tôi đã tạo một đối tượng mới và đặt tên x
cho đối tượng mới này. Đối tượng khác có giá trị là 24601
không còn có thể truy cập được bởi x
(hoặc bất kỳ tên nào khác trong trường hợp này):

Bất cứ khi nào chúng ta gán một giá trị mới cho một tên (trong ví dụ trên – x
) được liên kết với một int
đối tượng, chúng tôi thực sự thay đổi ràng buộc của tên đó thành một đối tượng khác.
Điều tương tự cũng áp dụng cho tuple
s, chuỗi (str
đối tượng), và bool
cũng vậy. Nói cách khác, int
(và các loại số khác như float
), tuple
, bool
và str
đối tượng là bất biến.
Hãy kiểm tra giả thuyết này. Điều gì xảy ra nếu chúng ta tạo một tuple
đối tượng, và sau đó cung cấp cho nó một giá trị khác?
>>> my_tuple = (1, 2, 3)
>>> id(my_tuple)
54263304
>>> my_tuple = (3, 4, 5)
>>> id(my_tuple)
56898184
giống như một int
đối tượng, chúng ta có thể thấy rằng nhiệm vụ của chúng ta thực sự đã thay đổi đối tượng mà tên my_tuple
là ràng buộc để.
Điều gì xảy ra nếu chúng ta cố gắng thay đổi một trong những tuple
các phần tử?
>>> my_tuple[0] = 'a new value'
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'tuple' object does not support item assignment
Như chúng ta có thể thấy, Python không cho phép chúng ta sửa đổi my_tuple
nội dung của nó, vì nó là bất biến.
Các đối tượng có thể thay đổi trong Python
Một số loại trong Python có thể được sửa đổi sau khi tạo và chúng được gọi là có thể thay đổi. Ví dụ, chúng tôi biết rằng chúng tôi có thể sửa đổi nội dung của một list
vật:
>>> my_list = [1, 2, 3]
>>> my_list[0] = 'a new value'
>>> my_list
['a new value', 2, 3]
Điều đó có nghĩa là chúng ta thực sự đã tạo một đối tượng mới khi gán một giá trị mới cho phần tử đầu tiên của my_list
? Một lần nữa, chúng ta có thể sử dụng id
để kiểm tra:
>>> my_list = [1, 2, 3]
>>> id(my_list)
55834760
>>> my_list
[1, 2, 3]
>>> my_list[0] = 'a new value'
>>> id(my_list)
55834760
>>> my_list
['a new value', 2, 3]
Vì vậy, nhiệm vụ đầu tiên của chúng tôi my_list = [1, 2, 3]
đã tạo một đối tượng trong địa chỉ 55834760
với các giá trị của 1
, 2
và 3
:

Sau đó chúng tôi đã sửa đổi phần tử đầu tiên của điều này list
đối tượng sử dụng my_list[0] = 'a new value'
nghĩa là – mà không cần tạo mới list
vật:

Bây giờ, chúng ta hãy tạo hai tên – x
và y
cả hai liên kết với nhau list
vật. Chúng tôi có thể xác minh rằng bằng cách sử dụng is
hoặc bằng cách kiểm tra rõ ràng id
S:
>>> x = y = [1, 2]
>>> x is y
True
>>> id(x)
18349096
>>> id(y)
18349096
>>> id(x) == id(y)
True
Điều gì xảy ra bây giờ nếu chúng ta sử dụng x.append(3)
? Đó là, nếu chúng ta thêm một phần tử mới (3
) cho đối tượng theo tên của x
?
Sẽ x
bằng cách thay đổi? Sẽ y
?
Chà, như chúng ta đã biết, về cơ bản chúng là hai tên của cùng một đối tượng:

Vì đối tượng này đã được thay đổi nên khi kiểm tra tên của nó, chúng ta có thể thấy giá trị mới:
>>> x.append(3)
>>> x
[1, 2, 3]
>>> y
[1, 2, 3]
Lưu ý rằng x
và y
có giống nhau id
như trước đây – vì chúng vẫn bị ràng buộc với nhau list
vật:
>>> id(x)
18349096
>>> id(y)
18349096

Ngoài ra list
s, các loại Python khác có thể thay đổi bao gồm set
cát dict
S.
từ điển (dict
đối tượng) thường được sử dụng trong Python. Xin nhắc lại, chúng tôi định nghĩa chúng như sau:
my_dict = {"name": "Omer", "number_of_pets": 1}
Sau đó, chúng ta có thể truy cập một phần tử cụ thể bằng tên khóa của nó:
>>> my_dict["name"]
'Omer'
Từ điển là có thể thay đổi, vì vậy chúng ta có thể thay đổi nội dung của chúng sau khi tạo. Tại bất kỳ thời điểm nào, một khóa trong từ điển chỉ có thể trỏ đến một phần tử:
>>> my_dict["name"] = "John"
>>> my_dict["name"]
'John'
Thật thú vị khi lưu ý rằng một khóa của từ điển phải là bất biến:
>>> my_dict = {[1,2]: "Hello"}
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'list'
Tại sao lại như vậy?
Hãy xem xét tình huống giả định sau (lưu ý: đoạn trích bên dưới thực sự không thể chạy được trong Python):
>>> x = [1, 2]
>>> y = [1, 2, 3]
>>> my_dict = {x: 'a', y: 'b'}
Cho đến nay, mọi thứ dường như không tệ lắm. Chúng tôi cho rằng nếu chúng tôi truy cập my_dict
với chìa khóa của [1, 2]
ta sẽ nhận được giá trị tương ứng của 'a'
và nếu chúng ta truy cập khóa [1, 2, 3]
chúng ta sẽ nhận được giá trị 'b'
.
Bây giờ, điều gì sẽ xảy ra nếu chúng ta cố gắng sử dụng:
>>> x.append(3)
Trong trường hợp này, x
sẽ có giá trị của [1, 2, 3]
và y
cũng sẽ có giá trị của [1, 2, 3]
. Chúng ta sẽ nhận được gì khi yêu cầu my_dict[[1, 2, 3]]
? Sẽ là như vậy 'a'
hoặc 'b'
? Để tránh những trường hợp như vậy, Python đơn giản là không cho phép các khóa từ điển có thể thay đổi được.
Hãy thử áp dụng kiến thức của chúng ta vào một trường hợp thú vị hơn một chút.
Dưới đây, chúng tôi định nghĩa một list
(một có thể thay đổi đối tượng) và một tuple
(một bất biến vật). Các list
Bao gồm một tuple
và tuple
Bao gồm một list
:
>>> my_list = [(1, 1), 2, 3]
>>> my_tuple = ([1, 1], 2, 3)
>>> type(my_list)
<class 'list'>
>>> type(my_list[0])
<class 'tuple'>
>>> type(my_tuple)
<class 'tuple'>
>>> type(my_tuple[0])
<class 'list'>
Càng xa càng tốt. Bây giờ, hãy thử tự suy nghĩ – điều gì sẽ xảy ra khi chúng ta cố gắng thực hiện từng câu lệnh sau đây?
(1) >>> my_list[0][0] = 'Changed!'
(2) >>> my_tuple[0][0] = 'Changed!'
Trong tuyên bố (1), những gì chúng tôi đang cố gắng làm là thay đổi my_list
phần tử đầu tiên của ‘, đó là, một tuple
. Từ một tuple
Là bất biếnnỗ lực này chắc chắn sẽ thất bại:
>>> my_list[0][0] = 'Changed!'
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'tuple' object does not support item assignment
Lưu ý rằng những gì chúng tôi đã cố gắng làm là không phải thay đổi danh sách, mà thay vào đó – thay đổi nội dung của phần tử đầu tiên.
Hãy xem xét tuyên bố (2). Trong trường hợp này, chúng tôi đang truy cập my_tuple
yếu tố đầu tiên của, đó là một list
, và sửa đổi nó. Hãy điều tra thêm trường hợp này và xem địa chỉ của các phần tử này:
>>> my_tuple = ([1, 1], 2, 3)
>>> id(my_tuple)
20551816
>>> type(my_tuple[0])
<class 'list'>
>>> id(my_tuple[0])
20446248

Khi chúng ta thay đổi my_tuple[0][0]
chúng tôi không thực sự thay đổi my_tuple
ở tất cả! Thật vậy, sau khi thay đổi, my_tuple
phần tử đầu tiên của vẫn sẽ là đối tượng có địa chỉ trong bộ nhớ là 20446248
. Tuy nhiên, chúng tôi thay đổi giá trị của đối tượng đó:
>>> my_tuple[0][0] = 'Changed!'
>>> id(my_tuple)
20551816
>>> id(my_tuple[0])
20446248
>>> my_tuple
(['Changed!', 1], 2, 3)
id(my_tuple)
và id(my_tuple[0])
giữ nguyên sau khi thay đổi
Vì chúng tôi chỉ sửa đổi giá trị của my_tuple[0]
đó là một đột biến list
đối tượng, thao tác này thực sự đã được Python cho phép.
Trong bài đăng này, chúng ta đã tìm hiểu về các đối tượng Python. Chúng tôi đã nói rằng trong Python tất cả mọi thứ là một đối tượngvà phải sử dụng id
và is
để hiểu sâu hơn về những gì đang diễn ra bên trong khi sử dụng Python để tạo và sửa đổi các đối tượng.
Chúng tôi cũng đã học được sự khác biệt giữa có thể thay đổi các đối tượng, có thể được sửa đổi sau khi tạo và bất biến đối tượng, mà không thể.
Chúng tôi đã thấy rằng khi chúng tôi yêu cầu Python sửa đổi một đối tượng bất biến được liên kết với một tên nhất định, chúng tôi thực sự tạo một đối tượng mới và liên kết tên đó với nó.
Sau đó, chúng tôi đã tìm hiểu lý do tại sao các khóa từ điển phải được bất biến trong Python.
Hiểu cách Python “nhìn thấy” các đối tượng là chìa khóa để trở thành một lập trình viên Python giỏi hơn. Tôi hy vọng bài đăng này đã giúp bạn trên hành trình thành thạo Python.
Omer Rosenbaum, bơiGiám đốc Công nghệ của. Chuyên gia đào tạo mạng và Người sáng lập Học viện An ninh Checkpoint. Tác giả của Mạng máy tính (bằng tiếng Do Thái). Ghé thăm tôi Kênh Youtube.