Python vượt qua tham chiếu
Có hai cách biến phổ biến được sử dụng để truyền đối số trong C/C++/Perl là truyền giá trị và truyền tham chiếu. Python sử dụng một cách tương tự như vậy dựa trên kiểu dữ liệu truyền vào là đối tượng bất biến hoặc đối tượng có thể thay đổi mà sử dụng giá trị truyền hoặc tham chiếu tương ứng. Hơn nữa, trong Python công việc truyền đối số cũng trở nên linh hoạt hơn nhiều nhờ vào việc hỗ trợ 2 ký tự ‘*’ và ‘**’ khi gọi hàm. Nhờ đó, chúng ta không phải viết tường minh hay cần biết trước số lượng tham số đầu vào
Một câu hỏi nhạt toẹt của nhà phỏng vấn có thể được đưa ra (với người phỏng vấn thông thường có kiến thức từ ngôn ngữ khác như Java, PHP hay C++, hoặc một chuyên gia Python thực sự và hỏi để kiểm tra xem bạn có băn khoăn không Show Tuyển trăn nhiều vị trí lương cao Python sử dụng gọi theo giá trị hay gọi theo tham chiếu?Hai khái niệm này thực sự không tồn tại trong Python, bạn có thể đào tung cả trang tài liệu của Python cũng sẽ không thấy nói gì về khái niệm này. News is. nó không có thật. Nó không cần thiết. bạn chỉ cần hiểu chức năng hoạt động thế nào, cách Python sử dụng “name binding”. Còn không nên ngồi cãi nhau về “call-by-reference”, “call-by-value” làm gì cho mất thời gian, vô tác dụng
Call by XYZ là cái gì?Mọi khái niệm viết sau đây không tồn tại trong Python, các thuật ngữ được viết với “từ vựng” của ngôn ngữ lập trình khác Trong một số ngôn ngữ như C, C++, khi gọi hàm ta có truyền vào các “tham số” (truyền đối số), nếu hàm đó nhận vào một mảng (trong Python hiểu nôm na là danh sách), thì trong hàm, ta sẽ Kiểu 1 update(danh_sach) Kiểu 2 update(&danh_sach) Với câu gọi hàm (hàm gọi) thứ nhất ta gọi hàm với giá trị (giá trị) của biến update(&danh_sach)0. Mọi sự thay đổi trong hàm thực hiện trên đối số được gọi là thực hiện trên bản sao của update(&danh_sach)0 Câu gọi hàm thứ hai ta gọi hàm với con trỏ (con trỏ) đến biến update(&danh_sach)0 hay còn gọi là tham chiếu. Mọi thay đổi sẽ thay đổi trực tiếp trên update(&danh_sach)0 Trình lập trình ngôn ngữ này bị ảnh hưởng bởi C thường xuyên cắt giảm khái niệm “con trỏ” để tránh gây phức tạp, vì vậy khi gọi hàm sẽ mặc định sử dụng 1 trong 2 kiểu trên. Hoặc sử dụng một chế độ hoàn toàn khác Ví dụ
Call by và pass by
Chỉ là hai cách tập trung khác nhau vào một công việc. gọi hàm với các đối số Gọi hàm trong Python active thế nào?Nếu bắt buộc phải đưa ra một từ khóa, thì đó là các đối số sẽ được “vượt qua nhiệm vụ”. Để hiểu rõ nhiệm vụ Python làm gì, bạn cần hiểu về khái niệm tên và ràng buộc trong Python Cách hoạt động của tên và ràng buộcx = 4 y = x x = x + 1 print(x, y) update(&danh_sach)4 là mấy và update(&danh_sach)5 là mấy? Mã này đọc theo thuật ngữ của Python như sau
Unknown results at here. update(&danh_sach)4 là 5, update(&danh_sach)5 là 4. Chú ý rằng update(&danh_sach)5 không đi theo update(&danh_sach)4, cũng không liên kết với update(&danh_sach)4, nó liên kết với đối tượng mà update(&danh_sach)4 liên kết tại thời điểm đó Xem ví dụ sau tương tự, nhưng chắc chắn khác L = [1,2,3] K = L L[0] = 9 print(L, K) x = 4 y = x x = x + 1 print(x, y)7 là mấy? Điều này sẽ rõ ràng, phải là câu hỏi phỏng vấn mặc định để thiết lập trình viên Python chứ không phải vài câu trộn lẫn như tiêu đề bài viết này. Vì sao? Please read this đoạn mã theo thuật ngữ Python
Hãy nhớ x = 4 y = x x = x + 1 print(x, y)7 và x = 4 y = x x = x + 1 print(x, y)8 chỉ là 2 tên cùng liên kết với một đối tượng, khi đối tượng này bị thay đổi, dù sử dụng qua tên x = 4 y = x x = x + 1 print(x, y)7 hay tên x = 4 y = x x = x + 1 print(x, y)8, thì thay đổi đó là thực hiện trên đối tượng đó. Kết quả tức thời sẽ cho x = 4 y = x x = x + 1 print(x, y)7 và x = 4 y = x x = x + 1 print(x, y)8 giống nhau (hay chính xác hơn, chúng là một). Sử dụng hàm L = [1,2,3] K = L L[0] = 9 print(L, K)8 sẽ giúp hiểu rõ hơn khi nói về đối tượng và tên >>> L = [1,2,3] >>> K = L >>> L[0] = 9 >>> print(L, K) [9, 2, 3] [9, 2, 3] >>> id(L) 4326049992 >>> id(K) 4326049992 >>> L is K True L = [1,2,3] K = L L[0] = 9 print(L, K)8 sẽ trả lại một số ID ( chắc chắn là duy nhất) gắn liền với đối tượng mà cái tên đó đang ràng buộc Cơ chế hoạt động của chức năng>>> def change(numb, ns): ... numb = numb + 1 ... ns[0] = 0 ... return None ... >>> N = 9 >>> L = [1,2,3] >>> change(N, L) >>> print(N, L) 9 [0, 2, 3] Cơ chế gọi chức năng của Python hoạt động như sau
Vậy làm sao để không thay đổi danh sách L và thu về một danh sách mới sau khi gọi hàm? >>> def change(L): ... L = L[:] # slicing là một cách đơn giản để tạo một bản shallow copy ... L[0] = 0 ... return L ... >>> newL = change(L) >>> print(L) [1, 2, 3] >>> print(newL) [0, 2, 3] note. Nếu danh sách L bao gồm các đối tượng có thể thay đổi (xem ở dưới), cần sử dụng hàm >>> L = [1,2,3] >>> K = L >>> L[0] = 9 >>> print(L, K) [9, 2, 3] [9, 2, 3] >>> id(L) 4326049992 >>> id(K) 4326049992 >>> L is K True8 trong thư viện chuẩn >>> L = [1,2,3] >>> K = L >>> L[0] = 9 >>> print(L, K) [9, 2, 3] [9, 2, 3] >>> id(L) 4326049992 >>> id(K) 4326049992 >>> L is K True9 Một số kiểu dữ liệu trong Python không cho phép thay đổi giá trị của nó sau khi tạo ra (bất biến) như int, float, str, NoneType, bool, tuple. Vì vậy, mỗi lần “thay đổi”, ta sẽ tạo ra một đối tượng mới chứa giá trị mới >>> N = 9 >>> id(N) 4297624192 >>> N = N + 2 >>> id(N) 4297624256 >>> N 11 >>> T1 = (1,2,3) >>> id(T1) 4326100280 >>> T1 = T1 + (3,4,5) >>> id(T1) 4325883048 >>> print(T1) (1, 2, 3, 3, 4, 5) Các loại dữ liệu khác cho phép thay đổi sau khi tạo ra (có thể thay đổi). danh sách, dict, thiết lập >>> L = [1,2,3] >>> id(L) 4326050504 >>> L.extend([3,4,5]) >>> id(L) 4326050504 >>> print(L) [1, 2, 3, 3, 4, 5] Với kiểu có thể thay đổi, cần đặc biệt chú ý cho phép toán bất kỳ trả về đối tượng mới, cho phép toán bất kỳ đối tượng thay đổi hiện tại >>> L = [1,2,3] >>> id(L) 4326050568 >>> L = L + [3,4,5] >>> id(L) 4326095240 >>> L [1, 2, 3, 3, 4, 5] >>> def change(numb, ns): ... numb = numb + 1 ... ns[0] = 0 ... return None ... >>> N = 9 >>> L = [1,2,3] >>> change(N, L) >>> print(N, L) 9 [0, 2, 3]0, >>> def change(numb, ns): ... numb = numb + 1 ... ns[0] = 0 ... return None ... >>> N = 9 >>> L = [1,2,3] >>> change(N, L) >>> print(N, L) 9 [0, 2, 3]1 của danh sách đều thay đổi phương thức gọi đối tượng. Magic >>> def change(numb, ns): ... numb = numb + 1 ... ns[0] = 0 ... return None ... >>> N = 9 >>> L = [1,2,3] >>> change(N, L) >>> print(N, L) 9 [0, 2, 3]2 list with list, sinh ra một danh sách mới Python sử dụng chuyển theo phép gán, gọi theo tham chiếu đối tượngVượt qua nhiệm vụ là khái niệm lấy từ , khi đó người ta bắt buộc phải giải thích khái niệm này cho những người đã biết ngôn ngữ lập trình khác. Tên trong hàm sẽ liên kết với các đối tượng mà đối số đang liên kết tới Trong hướng dẫn Python, có viết – yup, tôi đã nói dối 😒 :
Liệu bạn có thể sử dụng một thuật ngữ khác là “gọi tên” ?? Chốt, thông tinĐể khỏi đau đầu về những điều này, chỉ cần nắm chắc các khái niệm >>> def change(numb, ns): ... numb = numb + 1 ... ns[0] = 0 ... return None ... >>> N = 9 >>> L = [1,2,3] >>> change(N, L) >>> print(N, L) 9 [0, 2, 3]3, >>> def change(numb, ns): ... numb = numb + 1 ... ns[0] = 0 ... return None ... >>> N = 9 >>> L = [1,2,3] >>> change(N, L) >>> print(N, L) 9 [0, 2, 3]4, >>> def change(numb, ns): ... numb = numb + 1 ... ns[0] = 0 ... return None ... >>> N = 9 >>> L = [1,2,3] >>> change(N, L) >>> print(N, L) 9 [0, 2, 3]5, >>> def change(numb, ns): ... numb = numb + 1 ... ns[0] = 0 ... return None ... >>> N = 9 >>> L = [1,2,3] >>> change(N, L) >>> print(N, L) 9 [0, 2, 3]6 là đủ biết chương trình chạy thế nào. You don't know Python name is call-by-gì? Trên internet có nhiều nơi hỏi đáp, cố đưa ra một cái tên, nhưng những cái tên đó không có trong tài liệu chính của Python |