Điều quan trọng là phải hiểu cơ chế truyền tham số trong Python, cơ chế này thường cho phép chúng ta mắc ít lỗi hơn và nâng cao hiệu quả khi viết mã
Truyền theo giá trị so với Truyền theo tham chiếuNếu bạn có nền tảng ngôn ngữ lập trình khác, chẳng hạn như C/C++, thì dễ hiểu rằng có hai kiểu truyền tham số phổ biến. pass-by-value và pass-by-reference
- giá trị vượt qua. Sao chép giá trị của tham số và chuyển nó vào biến mới trong hàm
- chuyển qua tham chiếu. Truyền tham chiếu của tham số cho biến mới, để biến ban đầu và biến mới sẽ trỏ đến cùng một địa chỉ bộ nhớ
Vậy làm cách nào để truyền tham số hoạt động trong Python?
Trước khi trả lời câu hỏi này, trước tiên chúng ta hãy hiểu các nguyên tắc cơ bản của các biến và phép gán trong Python
Các biến và bài tập trong PythonHãy bắt đầu bằng cách xem ví dụ mã Python sau
a = 1
b = a
a = a + 1
Ở đây, 1
đầu tiên được gán cho a
, tức là, a
trỏ tới đối tượng 1
, như thể hiện trong sơ đồ sau
Khi đó,
l1 = [1, 2, 3]
l2 = l1
l1.append[4]
l1
[1, 2, 3, 4]
l2
[1, 2, 3, 4]
0 có nghĩa là, hãy để biến l1 = [1, 2, 3]
l2 = l1
l1.append[4]
l1
[1, 2, 3, 4]
l2
[1, 2, 3, 4]
1 đồng thời trỏ đến đối tượng 1
. Lưu ý ở đây rằng các đối tượng trong Python có thể được trỏ tới hoặc tham chiếu bởi nhiều biến. Bây giờ lưu đồ trông như thế nàyCuối cùng là câu lệnh
l1 = [1, 2, 3]
l2 = l1
l1.append[4]
l1
[1, 2, 3, 4]
l2
[1, 2, 3, 4]
3. Cần lưu ý rằng các kiểu dữ liệu Python, chẳng hạn như số nguyên [int], chuỗi [string], v.v. , là bất biến. Vì vậy, l1 = [1, 2, 3]
l2 = l1
l1.append[4]
l1
[1, 2, 3, 4]
l2
[1, 2, 3, 4]
3, không tăng giá trị của a
lên 1, nhưng có nghĩa là một đối tượng mới có giá trị là l1 = [1, 2, 3]
l2 = l1
l1.append[4]
l1
[1, 2, 3, 4]
l2
[1, 2, 3, 4]
6 được tạo và a
trỏ tới nó. Nhưng l1 = [1, 2, 3]
l2 = l1
l1.append[4]
l1
[1, 2, 3, 4]
l2
[1, 2, 3, 4]
1 vẫn không thay đổi và vẫn trỏ đến đối tượng 1
Tại thời điểm này, bạn có thể thấy rằng một phép gán đơn giản
l1 = [1, 2, 3]
l2 = l1
l1.append[4]
l1
[1, 2, 3, 4]
l2
[1, 2, 3, 4]
0 không có nghĩa là một đối tượng mới được tạo lại, mà là cùng một đối tượng được trỏ hoặc tham chiếu bởi nhiều biếnĐồng thời, trỏ đến cùng một đối tượng không có nghĩa là hai biến bị ràng buộc với nhau. Nếu bạn gán lại một trong các biến, nó sẽ không ảnh hưởng đến giá trị của các biến khác
Bây giờ chúng ta hãy xem một ví dụ về danh sách
l1 = [1, 2, 3]
l2 = l1
l1.append[4]
l1
[1, 2, 3, 4]
l2
[1, 2, 3, 4]
Lúc đầu, chúng tôi để danh sách
l = [1, 2, 3]
del l
1 và l = [1, 2, 3]
del l
2 trỏ đến đối tượng [1, 2, 3] cùng một lúcVì danh sách có thể thay đổi, nên
l = [1, 2, 3]
del l
3 không tạo danh sách mới, nó chỉ chèn phần tử 4 vào cuối danh sách ban đầu, danh sách này trở thành [1, 2, 3, 4]. Do l = [1, 2, 3]
del l
1 và l = [1, 2, 3]
del l
2 trỏ đến danh sách này cùng một lúc nên sự thay đổi của danh sách sẽ được phản ánh đồng thời ở hai biến là l = [1, 2, 3]
del l
1 và l = [1, 2, 3]
del l
2, khi đó giá trị của l = [1, 2, 3]
del l
1 và l = [1, 2, 3]
del l
2 sẽ trở thành [1, 2, Ngoài ra, lưu ý rằng các biến trong Python có thể bị xóa, nhưng các đối tượng không thể bị xóa. Ví dụ đoạn mã sau
l = [1, 2, 3]
del l
def my_func1[b]:0 xóa biến
b = 2a = 1
my_func1[a]
a
1
def my_func1[b]:1, và bạn không thể truy cập vào
b = 2a = 1
my_func1[a]
a
1
def my_func1[b]:1 từ bây giờ, nhưng đối tượng [1, 2, 3] vẫn tồn tại. Khi một chương trình Python chạy, hệ thống thu gom rác của chính nó sẽ theo dõi mọi tham chiếu đối tượng. Nếu [1, 2, 3] được tham chiếu ở những nơi khác ngoài
b = 2a = 1
my_func1[a]
a
1
def my_func1[b]:1, nó sẽ không được thu thập, nếu không, nó sẽ được thu thập
b = 2a = 1
my_func1[a]
a
1
Vì vậy, trong Python
- Việc gán một biến chỉ có nghĩa là biến đó trỏ đến một đối tượng và không có nghĩa là đối tượng được sao chép vào biến;
- Thay đổi các đối tượng có thể thay đổi [danh sách, từ điển, bộ, v.v. ] ảnh hưởng đến tất cả các biến trỏ đến đối tượng đó
- Đối với các đối tượng không thay đổi [chuỗi, int, bộ dữ liệu, v.v. ], giá trị của tất cả các biến trỏ đến đối tượng luôn giống nhau và không thay đổi. Nhưng khi giá trị của một đối tượng bất biến được cập nhật bởi một số thao tác [+= v.v. ], một đối tượng mới được trả về
- Các biến có thể bị xóa, nhưng các đối tượng không thể bị xóa
Hãy xem trích dẫn chính thức của Python
“Hãy nhớ rằng các đối số được truyền bằng phép gán trong Python. Vì phép gán chỉ tạo tham chiếu đến các đối tượng, nên không có bí danh giữa tên đối số trong trình gọi và callee, do đó không có tham chiếu gọi theo tham chiếu mỗi Se. ”
Truyền đối số của Python được truyền theo phép gán hoặc truyền theo tham chiếu đối tượng. Các kiểu dữ liệu trong Python đều là đối tượng nên khi truyền tham số chỉ để biến mới và biến ban đầu trỏ về cùng một đối tượng, không có chuyện truyền giá trị hay truyền tham chiếu
Ví dụ
def my_func1[b]:
b = 2a = 1
my_func1[a]
a
1
Tham số truyền vào đây làm cho các biến a
và
l1 = [1, 2, 3]
l2 = l1
l1.append[4]
l1
[1, 2, 3, 4]
l2
[1, 2, 3, 4]
1 trỏ đến đối tượng 1
cùng một lúc. Nhưng khi chúng ta đến def my_func1[b]:7, hệ thống sẽ tạo một đối tượng mới với giá trị là
b = 2a = 1
my_func1[a]
a
1
l1 = [1, 2, 3]
l2 = l1
l1.append[4]
l1
[1, 2, 3, 4]
l2
[1, 2, 3, 4]
6 và để l1 = [1, 2, 3]
l2 = l1
l1.append[4]
l1
[1, 2, 3, 4]
l2
[1, 2, 3, 4]
1 trỏ tới nó; . Vì vậy, giá trị của a không thay đổi, nó vẫn là 1
Tuy nhiên, khi một đối tượng có thể thay đổi được truyền dưới dạng tham số cho hàm, việc thay đổi giá trị của đối tượng có thể thay đổi sẽ ảnh hưởng đến tất cả các biến trỏ đến nó. Ví dụ
def my_func3[l2]:
l2.append[4]l1 = [1, 2, 3]
my_func3[l1]
l1
[1, 2, 3, 4]
Ở đây
l = [1, 2, 3]
del l
1 và l = [1, 2, 3]
del l
2 đầu tiên cả hai đều trỏ đến danh sách có giá trị [1, 2, 3]. Tuy nhiên, do danh sách có nhiều biến khi hàm def my_func3[l2]:5 được thực thi và một phần tử mới
l2.append[4]l1 = [1, 2, 3]
my_func3[l1]
l1
[1, 2, 3, 4]
def my_func3[l2]:6 được thêm vào cuối danh sách nên giá trị của các biến
l2.append[4]l1 = [1, 2, 3]
my_func3[l1]
l1
[1, 2, 3, 4]
l = [1, 2, 3]
del l
1 và l = [1, 2, 3]
del l
2 cũng bị thay đổiTuy nhiên, ví dụ sau đây, dường như thêm một phần tử mới vào danh sách, lại mang lại kết quả khác biệt đáng kể
def my_func4[l2]:
l2 = l2 + [4]l1 = [1, 2, 3]
my_func4[l1]
l1
[1, 2, 3]
Điều này là do câu lệnh
def my_func3[l2]:9, có nghĩa là một danh sách mới với "phần tử 4 được thêm vào cuối" được tạo và
l2.append[4]l1 = [1, 2, 3]
my_func3[l1]
l1
[1, 2, 3, 4]
l = [1, 2, 3]
del l
2 trỏ tới đối tượng mới nàyPhần kết luậnKhông giống như các ngôn ngữ khác, việc truyền tham số trong Python không phải theo giá trị hay theo tham chiếu, mà theo phép gán hoặc tham chiếu đến các đối tượng
Cần lưu ý rằng phép gán hoặc chuyển tham chiếu của đối tượng ở đây không trỏ đến một địa chỉ bộ nhớ cụ thể mà là một đối tượng cụ thể
- Nếu một đối tượng có thể thay đổi, khi nó thay đổi, tất cả các biến trỏ đến đối tượng này sẽ thay đổi theo
- Nếu đối tượng là bất biến, một phép gán đơn giản chỉ có thể thay đổi giá trị của một trong các biến, khiến các biến còn lại không bị ảnh hưởng
Rõ ràng muốn thay đổi giá trị của biến thông qua hàm thường có 2 cách
- Một là chuyển trực tiếp vào một kiểu dữ liệu biến [chẳng hạn như danh sách, từ điển, tập hợp] làm tham số và sửa đổi nó trực tiếp;
- Hai là tạo một biến mới để lưu giá trị đã sửa, sau đó trả về biến ban đầu
Trong công việc thực tế, chúng tôi thích sử dụng cái sau hơn, vì cách diễn đạt của nó rõ ràng và ít sai sót hơn