Sự thay đổi của List trong vòng lặp ở Python

Em chào mọi người, em có thực hiện như hai ví dụ này.
Đối với code 1, thì em sử dụng a_listWord = [] thì list lại không thay đổi sau khi thoát hàm
Nhưng khi em dùng a_listWord.clear() thì hàm lại thay đổi.

Một ví dụ khác mà em làm là

a = [1,2,3,4,5]
print(a)
for i in a:
    i = i+1
print(a)
a = [1,2,3,4,5]
print(a)
for i in range(len(a)):
    a[i] =  a[i] + 1
print(a)

Ở ví dụ bạn đưa, function resetList chỉ đơn giản là in cái gì đó ra trong lúc nó chạy, chạy xong thì thôi, chứ không return ra cái gì cả.

Cụ thể hơn, cái a_listWord mà được đưa vào tham số của resetList, khi hàm đó chạy, thì những thay đổi của cái a_listWord chỉ nằm bên trong cái hàm đó thôi, khi hàm chạy xong thì nó quay lại bình thường.

Bạn thử thêm dòng return a_listWord cho hàm resetList thử xem

1 Like

Với listTest = [1, 9, 3], thì khi gọi resetList(listTest...), a_listWordlistTest cùng chỉ tới biến listTest.
Trường hợp 1, a_listWord = [], thì lúc này a_listWord chỉ tới một chỗ mới chứa [], listTest vẫn giữ như cũ.
Trường hợp 2, a_listWord.clear(), lúc này a_listWord vẫn trỏ tới testList nên testList bị thay đổi thôi.

3 Likes

Anh cho em hỏi vậy khác nhau giữa việc thao tác trong hàm giữa
clear() và sử dụng = [] khác gì nhau ạ?
Vì hai cái như nhau nhưng 1 cái lại thay đổi khi đi qua hàm.

Vấn đề này được gọi là lỗi gì khi code không anh, iterator ạ?
Kiểu em thấy a_listWord đều được trỏ đến testList nhưng vì một cái là clear() nên tác động lên biến toàn cục bên ngoài và thay đổi hay sao anh

Câu trả lời của Mr Stanley00 bên trên đã trả lời luôn cho câu hỏi của bạn rồi á.

Mình trích lại 1 câu trên stackoverflow:

Doing alist = [] does not clear the list, just creates an empty list and binds it to the variable alist . The old list will still exist if it had other variable bindings.

4 Likes
  1. Giống như Java hay JS thôi :smiley: cái này có nhiều tên như pass-by-object-reference.
3 Likes

Cái này có thể gọi chung là lỗi người dùng/người lập trình nha. Cái tội ở chỗ dùng mà chẳng bao giờ đọc hướng dẫn sử dụng gì hết :stuck_out_tongue:

4 Likes

Cái link https://robertheaton.com/2014/02/09/pythons-pass-by-object-reference-as-explained-by-philip-k-d++++++++ick/ này khá hay nè .
Python mặc định pass by value cho các built-in type như int hay str

2 Likes

Dạ em cảm ơn nhiều ạ, nhiều lúc gặp mấy cái lỗi mà họ không có g.thích phần này nên em tưởng là lỗi iterator.

Anh có trang nào kiểu nói kỹ về nội dung và các lỗi hay gặp không.
Em kiểu học trên w3school nên nhiều khi chắc không được đầy đủ, cơ mà như vậy thì tùy vào việc em khai báo là = [] hay clear() mà Python sẽ thực hiện pass-by-reference hay là value đúng không anh?
Nên kiểu nhiều khi code cũng phải chú ý nó có làm thay đổi giá trị không.
Ví dụ 2 dưới comment của em cũng tương tự như vậy.
Cơ mà em cảm ơn anh nhiều ạ

Mình thấy sau 1 số comment nhưng bạn vẫn bị hiểu sai vấn đề.

Giải thích như sau (nhiều số ngôn ngữ bậc cao khác hiện nay cũng đều có chung concept, bạn có thể áp dụng cho nhiều NNLT khác nữa)
Để giải thích mình sẽ giả định như sau:
Ví dụ: Bạn khai báo 1 biến a = [] thì lúc này giá trị mà biến a chứa chính là địa chỉ đến 1 vùng nhớ trên RAM tạm gọi là (X) (trong C++ gọi là pointer) và biến a cũng đồng thời được lưu tại 1 vùng nhớ trên RAM tạm gọi là (A). Bạn chú ý kí hiệu mà mình sử dụng
Diễn giải trong bộ nhớ lúc này sẽ như sau.
a = (A) -> (X)

Khi đó mọi thao tác với đối tượng a qua các method/field mà a cung cấp (Ví dụ method clear) sẽ thao tác trên vùng nhớ (X).

Khi bạn pass a vào 2 function sau sẽ có 2 kết quả khác nhau

def func1(b):
    b.clear() // thao tác trên vùng nhớ (X)

def func2(b):
    b = []     // b được trỏ đến vùng nhớ (Y)
    b[0] = 1 // thao tác trên vùng nhớ (Y)

TH1: Khi bạn sử dụng func1:
lúc này Python sẽ thực hiện tạo mới 1 biến b tại được lưu tại vùng nhớ (B) và trỏ đến vùng nhớ (A)
Diễn giải trong bộ nhớ lúc này sẽ như sau.
a = (A) -> (X)
b = (B) -> (X)
vì a và b đều cùng trỏ đến (X) do đó mọi thao tác bởi các method đều sẽ được “đồng bộ”. thay đổi ở b sẽ thay đổi ở a

TH2: khi bạn sử dụng func2. Tình hình sẽ hơi khác chút. Ban đầu thì mọi thứ cũng sẽ giống func1.
diễn giải bộ nhớ trước khi line b = [] được thực thi
a = (A) -> (X)
b = (B) -> (X)
lệnh gán b = [] sẽ tạo mới 1 vùng nhớ (Y), sau đó giá trị mà b nắm giữ sẽ được tráo đổi sang trỏ tới vùng nhớ (Y)
Diễn giải trong bộ nhớ lúc này sẽ như sau.
a = (A) -> (X)
b = (B) -> (Y)
vì a và b hiện tại đã trỏ tới 2 vùng nhớ khác nhau do đó mọi thao tác trên b sẽ không phản ảnh lại cho a.

Hi vọng bạn sẽ hiểu. :wink:

PS: Có 1 câu như thế này do 1 a CEO ở cty dạy mình mà mình thấy rất hay, tóm gọn lại mọi vấn đề liên quan đến việc quản lí bộ nhớ của không chỉ riêng Python mà áp dụng chung cho nhiều NNLT khác như sau: “bản chất của biến (variable) chính là bộ nhớ RAM, bản chất của câu lệnh(function, operator, …) là CPU”. Nếu bạn hiểu được câu trên thì những cái như pointer, reference, pass-by-xxx,… chỉ là trò con nít.

4 Likes
83% thành viên diễn đàn không hỏi bài tập, còn bạn thì sao?