List biến đổi khi qua hàm?

Mình không học python, nhưng cách nghĩ của mình khác với bạn trên. Ví dụ đầu là List được pass by reference là đúng, không có gì phải nói.
Còn ví dụ thứ 2, thì chỗ

a_listNum = []

không phải tạo biến local mới, mà là thay đổi vùng nhớ trỏ tới. Thay vì tham số a_listNum trỏ tới vùng nhớ của list cũ, thì nó lại bị đổi sang vùng nhớ mới (rỗng).
Do đó khi ra khỏi hàm thì vùng nhớ trước đây không bị ảnh hưởng.

2 Likes

Việc bạn sử dụng gán bằng rỗng cho mục đích clearList là hoàn toàn không có tác dụng. Đây là cách làm sai. Các cách làm đúng: https://stackoverflow.com/questions/850795/different-ways-of-clearing-lists

Python dự vào kiểu dữ liệu (type) được pass vào để quyết định là dùng value hay reference.
Nói cho đơn giản, nếu đưa vào foo(a) mà a là integer thì nó lấy value của a để thực hiện công việc của hàm. Còn nếu a là list thì nó xử lý trên chính list đó.

Nếu theo cách hiểu của bạn thì sau khi a_listNum được trỏ tới vùng nhớ mới (rỗng) thì sau khi thoát khỏi hàm thì cái gì trỏ tới vùng nhớ cũ? Nếu a_listNum tự động trỏ tới vùng nhớ cũ thì mọi thao tác với a_listNum nằm trong hàm đâu liên quan gì tới ngoài hàm, như vậy nó hoàn toàn độc lập với thằng ngoài rồi -> vậy mình xem nó là biến local mới đâu có gì sai đâu.

Theo python chính thống thì không có khái niệm pointer, mà họ dùng khái niệm label.

5 Likes

Để rõ hơn cho ý mà nitro2 trả lời, bạn đọc qua 2 links này:

Cái này là giải thích về cái biến local ở ví dụ 2
https://www.programiz.com/python-programming/global-local-nonlocal-variables

Còn vì sao ở ví dụ 1, cũng là chạy lung tun bên trong function, nhưng behavior của nó không giống như ở ví dụ 2, là lại bị thay đổi, bạn tham khảo linh này

4 Likes

Vậy là để quyết định yếu tố value hay reference sẽ dựa vào type hả anh?
Như anh nói em thì

  • value: int, long, float, str chẳng hạn
  • reference: list, class

Trong trường hợp em clear list thì a ở đây cũng là list nhưng sao nó lại phân vào pass by value anh? Nếu như chỉ đơn giản nhìn vào phần parameter ở phần khai hàm thì dễ hơn. Đợt trước em có test thử sự khác nhau giữa việc dùng clear() và = [] rồi nhưng vẫn không thông lắm.
Ý thứ 2 là em thấy việc anh và anh kia nói hình như không khác nhau lắm, việc trỏ đến vùng nhớ khác hay là giá trị biến mới cũng như nhau :3

Dạ rồi, để em đọc cái này và ngẫm lại rồi có gì thắc mắc anh giúp đỡ thêm ạ, em cảm ơn.

Torng link có phần này, họ nhấn mạnh

In Python, data types can be either mutable (changeable) or immutable (unchangable). And while most of the data types we’ve worked with in introductory Python are immutable (including integers, floats, strings, Booleans, and tuples), lists and dictionaries are mutable. That means a global list or dictionary can be changed even when it’s used inside of a function ,

5 Likes

Dạ vâng, cái phần integers sẽ luôn không thay đổi thì em có biết, còn kiểu em đang bị rối chỗ list có khi đổi, có khi không.
Em nghĩ chắc vấn đề nằm ở chỗ em chưa hiểu cách pass by value hay pass by reference hoạt động ra sao, hay việc trỏ đến vùng nhớ khi nào.
Có gì để em đọc link anh trước rồi coi lại.

List luôn luôn pass by reference, việc bạn gán a_List = [] đã vô tình KHAI BÁO một vùng nhớ mới. Nên nó sai. Bạn đọc kỹ lại các nội dung trên.

1 Like

Hai biến tham chiếu khác nhau mà. Biến a_listNum bên ngoài với tham số a_listNum của hàm là 2 biến riêng biệt. Trong hàm a_listNum trỏ tới vùng nhớ khác thì ảnh hưởng gì tới a_listNum bên ngoài?

2 Likes

Bạn không nói tạo biến local mới thì lại mâu thuẫn với câu này sao?

a global list or dictionary can be changed even when it’s used inside of a function vì list là mutable

nên trong ví dụ 1, function nó modify trực tiếp giá trị của list

Trong ví dụ 2, funtion tạo 1 biến local “trùng tên” với list, hết function thì tan thành mây khói

2 Likes

Hai biến ở đây một là biến listNum (mình gõ nhầm) global với tham số a_listNum. Không có biến local nào cả.
Có vẻ như hai khái niệm này bị lẫn lộn:

  • Tạo biến local mới
  • Tạo vùng nhớ mới và cho a_listNum trỏ tới nó.
2 Likes

Ý của anh muốn nói với nhím là
listNum biến global
def clearList(a_listNum) a_listNum là tham số
Quy trình hoạt động là anh nói tức là khi chạy a_listNum sẽ nhận giá trị global của listNum,sau đó trỏ đến vùng nhớ mới chứ không phải tạo biến local mới.
Em đang đọc để coi lại sao nó không modify global của list thành [] mà trỏ đến vùng nhớ khác.
Các anh bàn luận trước có gì em đọc rồi trình bày lại nội dung xem em hiểu còn sai không ^^

Local variables can have the same name as global variables (those declared outside of any function). In that case, the global variable is inaccessible from within the function

Tức ở ví dụ 2, khi bạn tạo list a_listNum và gán gía trị [] cho nó, thì khi đó bạn không thể access biến global cùng tên đó nữa. Tức đó là 1 biến hoàn toàn khác, tức mục đích “clear list” của bạn đi sai hướng

2 Likes

Mình có googling lại một hồi thì tìm được link này. Về khoản pass biến vào hàm thì python khá giống với java.

Object references are passed by value.

Nghĩa là khi truyền tham chiếu, thì tạo ra thêm 1 bản copy biến tham chiếu và đưa vào hàm. Hai biến tham chiếu này cùng trỏ vào một vùng nhớ. Do đó nếu biến a_listNum (trong hàm) trỏ tới vùng nhớ khác là [] thì tham chiếu global listNum cũng không ảnh hưởng.

https://robertheaton.com/2014/02/09/pythons-pass-by-object-reference-as-explained-by-philip-k-dic
k/ (DNH chặn từ cuối trong link)

2 Likes

Có người nhắc mình là cách đây hơn 1 tháng, bạn này hỏi câu y chang: Sự thay đổi của List trong vòng lặp ở Python

Bạn này là “cô gái đến từ hôm qua” à?

Hi vọng tháng sau bạn không hỏi câu này nữa :zipper_mouth_face:

6 Likes

Hôm đó em có lấy ví dụ trường hợp clear() và thế bằng = [] nhưng em vẫn chưa hiểu sự khác nhau ấy anh.
Như qua bài này thì nội dung em sai là ở cách em gán biến thì nó không còn là pass by reference như cách biến hoạt động nữa.
Còn như về việc pass by reference hay value thì như anh thông tin cho em ở phía trên thì list, dict auto pass by reference

Em copy lại câu trả lời của 1 anh trong post trước cho mọi người tham khảo:

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.

-> Reply:
Đại khái là khi em clear() thì nó access same memory với vùng nhớ ngoài nên khi clear() nó thao tác trên cả biến global, còn = [] thì bản chất là em chỉ trỏ đến vùng mới thôi.
Có 1 câu anh đó nói về các vấn đề em đang mắc phải là:
"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” Tuy nhiên em vẫn chưa hiểu ý nghĩa của câu này lắm.
#comment: Em tag nhầm.

1 Like

Chắc bạn còn lấn cấn vì sao ko update cái tham chiếu. Trong Python chỉ có “name” và đối tượng (Java còn có primitive), tức là có tạo ra bao nhiêu tham chiếu cho 1 đối tượng thì cũng chỉ có 1 đối tượng mà thôi. Vì vậy bạn chỉ truyền đi có mỗi cái “tên” mà thôi :smiley: nhưng tham chiếu đó sẽ trỏ đến đối tượng (None cũng là đối tượng), rồi bạn muốn làm gì thì làm. Phần còn lại là mutable/immutable mà thôi.

Thuật ngữ đúng và hay dùng nhất là “call by object reference”.

3 Likes

Dạ đúng rồi ý em dạng như

def hamA(a_list):
   ....
   ....

print(hamA(listA)) chẳng hạn, thì listA được truyền đến cho a_list, sau đó tùy thuộc vào là kiểu dữ liệu gì thì nó sẽ mutable hay không

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