Trong Python, một trong những khái niệm quan trọng nhất cần hiểu là có sự khác biệt giữa các biến và các đối tượng được liên kết với các biến đó. Ý tưởng này phổ biến đối với nhiều ngôn ngữ lập trình, nhưng không phải ngôn ngữ như R hay Matlab, vì vậy đây là nơi mà những người mới sử dụng Python thường gặp rắc rối
Trong Python, các biến và đối tượng mà chúng trỏ tới thực sự sống ở hai vị trí khác nhau trong máy tính của bạn. Kết quả là, trong Python, tốt nhất nên coi các biến là trỏ đến các đối tượng mà chúng liên kết với, thay vì là các đối tượng đó. Cá nhân tôi luôn thích ví dụ máy tính của bạn là một nhà kho lớn, nơi các biến số chỉ là các mục trong sổ kiểm kê được sử dụng bởi người quản lý kho. biến cho bạn biết cách tìm thứ bạn muốn, nhưng bản thân nó không phải là thứ đó
Vì vậy, khi bạn tạo một danh sách mới, Python sẽ đặt danh sách đó ở đâu đó trong bộ nhớ, giống như cách bạn có thể đặt một thứ gì đó lớn trên giá trong nhà kho. Biến được liên kết với danh sách đó (giả sử, [3]: 0) thực sự chỉ lưu trữ vị trí của giá nơi đặt danh sách đó. Và bởi vì hành vi này là bình thường trong hầu hết các ngôn ngữ, bạn có thể không thấy nó được nhấn mạnh trong các hướng dẫn Python được viết bởi các lập trình viên không đến từ R
Lý do điều này quan trọng là nhiều biến có thể được chỉ vào cùng một đối tượng. Do đó, những thay đổi được thực hiện đối với một đối tượng thông qua một biến sẽ ảnh hưởng đến những gì bạn nhận được nếu bạn gọi các biến khác được chỉ vào đối tượng đó. Ví dụ
[1]:
# Make a new list x = [1, 2, 3] # Make new var Y, and assign it x. In R this would make a copy. y = x # Add to the end of the string x.append(4) # We see this new addition is now at end of x x
[1]:
[1, 2, 3, 4]
[2]:
# But look! It's also at the end of y! # That's because both variables are actually pointing to the same object in memory ("in the warehouse"), # so when you appended something to x, you changed the underlying object. And # since y was also pointed at that same object, when you next call y, it # "sees" those changes to the underlying list. y
[2]:
[1, 2, 3, 4]
Nếu nó hữu ích, đây là mô tả trực quan về những gì đang diễn ra
Đầu tiên, chúng tôi tạo một danh sách được liên kết với [3]: 1
Sau đó, chúng tôi tạo một var [3]: 2 cũng chỉ vào danh sách đó
Sau đó, chúng tôi sửa đổi danh sách thông qua [3]: 1, tạo ra một thay đổi cũng có thể nhìn thấy thông qua [3]: 2
Nếu bạn muốn tạo một bản sao của x, bạn sử dụng lệnh [3]: 5. Điều này tạo ra một danh sách hoàn toàn mới (một đối tượng mới trông giống như danh sách cũ nhưng có thể được đặt trên một giá khác) để những thay đổi đối với [3]: 1 sẽ không ảnh hưởng đến danh sách được liên kết với [3]: 2
[3]:
[1]: 7
[3]:
# Make a new list x = [1, 2, 3] # Make new var Y, and assign it x. In R this would make a copy. y = x # Add to the end of the string x.append(4) # We see this new addition is now at end of x x 1
Trực quan, chuỗi mã này trông như thế này
Bắt đầu với [3]: 1 và [3]: 2 như trước
Sau đó, chúng tôi thực hiện [1]: 70
Và sửa đổi [3]: 1, thay đổi những gì chúng tôi nhận được khi chúng tôi gọi [3]: 2, nhưng không phải là [1]: 70
Nếu bạn muốn xem liệu hai biến có trỏ đến cùng một thứ hay không, bạn có thể sử dụng toán tử [1]: 74, toán tử này sẽ kiểm tra xem hai biến có được trỏ đến cùng một vị trí trong bộ nhớ/cùng giá hay không
# Make a new list x = [1, 2, 3] # Make new var Y, and assign it x. In R this would make a copy. y = x # Add to the end of the string x.append(4) # We see this new addition is now at end of x x 2
# Make a new list x = [1, 2, 3] # Make new var Y, and assign it x. In R this would make a copy. y = x # Add to the end of the string x.append(4) # We see this new addition is now at end of x x 3
# Make a new list x = [1, 2, 3] # Make new var Y, and assign it x. In R this would make a copy. y = x # Add to the end of the string x.append(4) # We see this new addition is now at end of x x 2
# Make a new list x = [1, 2, 3] # Make new var Y, and assign it x. In R this would make a copy. y = x # Add to the end of the string x.append(4) # We see this new addition is now at end of x x 5
# Make a new list x = [1, 2, 3] # Make new var Y, and assign it x. In R this would make a copy. y = x # Add to the end of the string x.append(4) # We see this new addition is now at end of x x 6
# Make a new list x = [1, 2, 3] # Make new var Y, and assign it x. In R this would make a copy. y = x # Add to the end of the string x.append(4) # We see this new addition is now at end of x x 7
# Make a new list x = [1, 2, 3] # Make new var Y, and assign it x. In R this would make a copy. y = x # Add to the end of the string x.append(4) # We see this new addition is now at end of x x 6
# Make a new list x = [1, 2, 3] # Make new var Y, and assign it x. In R this would make a copy. y = x # Add to the end of the string x.append(4) # We see this new addition is now at end of x x 9
Lưu ý rằng [1]: 74 không giống như [1]: 76. [1]: 76 hỏi xem các mục trong danh sách mà hai biến trỏ tới có cùng giá trị hay không, trong khi [1]: 74 hỏi liệu hai biến có trỏ đến cùng một đối tượng không. Cho nên
[1]: 0
[1]: 1
[1]: 0
# Make a new list x = [1, 2, 3] # Make new var Y, and assign it x. In R this would make a copy. y = x # Add to the end of the string x.append(4) # We see this new addition is now at end of x x 9
[1]: 4
[1]: 5
[1]: 4
# Make a new list x = [1, 2, 3] # Make new var Y, and assign it x. In R this would make a copy. y = x # Add to the end of the string x.append(4) # We see this new addition is now at end of x x 5
Có thể thay đổi so với. Các loại bất biến
Bây giờ một nếp nhăn
Một số loại dữ liệu trong Python được gọi là “bất biến. ” Điều đó có nghĩa là một đối tượng, sau khi được tạo, thực sự không thể sửa đổi được. Kết quả là, nếu bạn muốn làm điều gì đó giống như sửa đổi đối tượng, Python phải tạo một đối tượng hoàn toàn mới nằm ở một vị trí mới
Ví dụ, các chuỗi là “bất biến. ” Vì vậy, nếu chúng tôi tạo một chuỗi, sau đó thử và sửa đổi nó, những gì chúng tôi thực sự đang làm là tạo một chuỗi mới có các tính năng mà chúng tôi muốn
Để minh họa, chúng ta có thể sử dụng hàm [1]: 79. Mọi đối tượng trong Python đều có một [1]: 79 duy nhất và do đó, khi hai biến trỏ đến cùng một đối tượng, thì [1]: 79 của các biến đó cũng sẽ trả về cùng một thứ
[1]: 8
[1]: 9
[1]: 8
[1, 2, 3, 4] 1
[1, 2, 3, 4] 2
[1, 2, 3, 4] 3
[1, 2, 3, 4] 2
[1, 2, 3, 4] 1
Như chúng ta có thể thấy, x và y trỏ đến cùng một đối tượng. Nhưng bây giờ hãy xem điều gì sẽ xảy ra nếu chúng ta sửa đổi chuỗi đó
[1, 2, 3, 4] 6
[1, 2, 3, 4] 7
[1, 2, 3, 4] 6
[1, 2, 3, 4] 9
[2]: 0
[2]: 1
[2]: 0
[2]: 3
Bây giờ [3]: 1 có giá trị mới là [1]: 79. Đó là bởi vì việc gọi [3]: 1 thực sự đã tạo ra một chuỗi mới là phiên bản viết hoa của “my string”, sau đó chúng tôi tạo điểm [3]: 1 cho đối tượng mới đó
Nhưng chuyện gì đã xảy ra với [3]: 2?
[2]: 4
[2]: 5
[2]: 4
[2]: 7
[2]: 8
[1, 2, 3, 4] 3
[2]: 8
[1, 2, 3, 4] 1
Như chúng ta có thể thấy, [3]: 2 vẫn trỏ vào chuỗi cũ và vẫn có cùng một [1]: 79. Điều này có thể được hình dung như [3]: 1 và [3]: 2 đều trỏ đến cùng một chuỗi
Sau đó, [3]: 1 được chuyển hướng đến một đối tượng mới (“CHUỖI CỦA TÔI”) vì các chuỗi là bất biến (có nghĩa là giá trị ban đầu của “chuỗi của tôi” không thể được sửa đổi tại chỗ)
Điều này minh họa một trong những sắc thái của Python. nếu bạn thay đổi một đối tượng có thể thay đổi, thay đổi đó sẽ lan truyền đến tất cả các biến trỏ đến đối tượng đã nói. Nhưng nếu bạn sửa đổi một đối tượng không thể thay đổi, một đối tượng mới sẽ thực sự được tạo, do đó thay đổi đó sẽ không thể truy cập được đối với các biến trỏ vào đối tượng cũ
Cái gì có thể thay đổi và cái gì là bất biến?
Dưới đây là danh sách nhanh các loại dữ liệu không thay đổi mà bạn có thể gặp phải
int
trôi nổi
số thập phân
phức tạp
bool
chuỗi
tuple
Và đây là các kiểu dữ liệu phổ biến có thể thay đổi
danh sách
bộ
từ điển
đối tượng do người dùng định nghĩa
mảng numpy
đối tượng gấu trúc
Làm thế nào để bạn nhớ điều này? . Có một số loại dữ liệu kỳ lạ cũng là các tập hợp không thể thay đổi (frozensets, như tên của nó, là "đóng băng" và do đó không thể thay đổi), nhưng bạn sẽ không bao giờ sử dụng chúng và nếu bạn làm
Chỉ một số thao tác là đột biến
OK, bây giờ là một sắc thái quan trọng. không phải tất cả các thao tác của các đối tượng có thể thay đổi đều thay đổi đối tượng thay vì tạo một đối tượng mới. Đôi khi, khi bạn làm điều gì đó với một đối tượng có thể thay đổi, bạn sẽ nhận lại một đối tượng mới. Các thao tác làm thay đổi một đối tượng hiện có, thay vì tạo một đối tượng mới, được gọi là "đột biến tại chỗ" hoặc chỉ là "đột biến". " Cho nên
Tất cả các thao tác của các loại bất biến tạo ra các đối tượng mới
Một số thao tác của các loại có thể thay đổi tạo đối tượng mới
Ví dụ: thêm nội dung nào đó vào cuối danh sách là một đột biến tại chỗ (danh sách hiện tại bị thay đổi). Nhưng làm những việc như nhân đôi danh sách bằng cách sử dụng # Make a new list x = [1, 2, 3] # Make new var Y, and assign it x. In R this would make a copy. y = x # Add to the end of the string x.append(4) # We see this new addition is now at end of x x 12 để tạo danh sách mới
# But look! It's also at the end of y! # That's because both variables are actually pointing to the same object in memory ("in the warehouse"), # so when you appended something to x, you changed the underlying object. And # since y was also pointed at that same object, when you next call y, it # "sees" those changes to the underlying list. y 2
# But look! It's also at the end of y! # That's because both variables are actually pointing to the same object in memory ("in the warehouse"), # so when you appended something to x, you changed the underlying object. And # since y was also pointed at that same object, when you next call y, it # "sees" those changes to the underlying list. y 3
# But look! It's also at the end of y! # That's because both variables are actually pointing to the same object in memory ("in the warehouse"), # so when you appended something to x, you changed the underlying object. And # since y was also pointed at that same object, when you next call y, it # "sees" those changes to the underlying list. y 2
# But look! It's also at the end of y! # That's because both variables are actually pointing to the same object in memory ("in the warehouse"), # so when you appended something to x, you changed the underlying object. And # since y was also pointed at that same object, when you next call y, it # "sees" those changes to the underlying list. y 5
# But look! It's also at the end of y! # That's because both variables are actually pointing to the same object in memory ("in the warehouse"), # so when you appended something to x, you changed the underlying object. And # since y was also pointed at that same object, when you next call y, it # "sees" those changes to the underlying list. y 6
[2]: 5
# But look! It's also at the end of y! # That's because both variables are actually pointing to the same object in memory ("in the warehouse"), # so when you appended something to x, you changed the underlying object. And # since y was also pointed at that same object, when you next call y, it # "sees" those changes to the underlying list. y 6
# But look! It's also at the end of y! # That's because both variables are actually pointing to the same object in memory ("in the warehouse"), # so when you appended something to x, you changed the underlying object. And # since y was also pointed at that same object, when you next call y, it # "sees" those changes to the underlying list. y 9
Tương tự, lấy một phần của danh sách sẽ cho bạn một danh sách mới
[2]: 0
[2]: 1
[2]: 0
[2]: 3
[2]: 4
[2]: 5
[2]: 4
# But look! It's also at the end of y! # That's because both variables are actually pointing to the same object in memory ("in the warehouse"), # so when you appended something to x, you changed the underlying object. And # since y was also pointed at that same object, when you next call y, it # "sees" those changes to the underlying list. y 9
Tài liệu của một hàm hầu như sẽ luôn cho bạn biết liệu một hàm có thay đổi danh sách tại chỗ hay không, và theo thời gian, bạn sẽ cảm nhận được cái gì biến đổi và cái gì không, nhưng tiếc là trong Python, không có cách nào rõ ràng để thay đổi.
Hàm và tham chiếu đối tượng
Một điều quan trọng khác cần biết là thực tế là tất cả các biến khác nhau đều có thể trỏ đến cùng một đối tượng được bảo toàn thông qua các lời gọi hàm (một hành vi được gọi là “chuyển qua tham chiếu đối tượng”). Vì vậy, nếu bạn chuyển một danh sách cho một hàm và hàm đó thao tác danh sách đó bằng cách sử dụng một đột biến tại chỗ, thì thay đổi đó sẽ ảnh hưởng đến bất kỳ biến nào đang trỏ đến cùng một đối tượng bên ngoài hàm đó
[2]: 8
[2]: 9
[2]: 8
[1, 2, 3, 4] 1
[1, 2, 3, 4] 2
[1, 2, 3, 4] 3
[1, 2, 3, 4] 2
[1, 2, 3, 4] 1
[1, 2, 3, 4] 6
[2]: 5
[1, 2, 3, 4] 6
[1, 2, 3, 4] 1
Bối rối?
Vâng, đó là hợp lý. Điều này thực sự khó khăn. Thành thật mà nói, bạn có thể sẽ không cảm thấy mình “hiểu” được điều này cho đến khi bạn chơi với nó nhiều (như chúng ta sẽ làm trong lớp. )