Các Vấn Đề Thường Gặp trong Python - [2] Đối Số Có Thể Thay Đổi
By JoeVu, at: 14:20 Ngày 11 tháng 1 năm 2023
Thời gian đọc ước tính: __READING_TIME__ phút


Python Đối số Khả Biến là một kiểu đối số có thể được thay đổi trong lời gọi hàm. Những đối số này được truyền theo tham chiếu và có thể được sửa đổi bên trong hàm. Điều này có thể gây ra các tác dụng phụ không mong muốn trong mã, dẫn đến các lỗi tiềm ẩn và hành vi không mong đợi.
Đối số Hàm Khả Biến
Đối số khả biến Python là một vấn đề phổ biến khi lập trình bằng Python, vì chúng có thể gây nhầm lẫn khi cố gắng gỡ lỗi mã.
Ví dụ, nếu một hàm lấy một danh sách làm đối số, việc thay đổi danh sách đó bên trong hàm cũng sẽ thay đổi nó bên ngoài hàm. Điều này có thể khó phát hiện trong quá trình gỡ lỗi nếu bạn không mong đợi giá trị thay đổi.
def append_to_list(a_list:list, element:int):
if element > 0:
a_list.append(element)
print ("Giá trị bên trong hàm: ", a_list)
a_list = [1, 2, 3]
append_to_list(a_list, 5)
print ("Giá trị bên ngoài hàm: ", a_list)
Kết quả
Giá trị bên trong hàm: [1, 2, 3, 5]
Giá trị bên ngoài hàm: [1, 2, 3, 5]
Vì hàm append_to_list() đã sửa đổi danh sách gốc bằng cách thêm phần tử vào nó nếu phần tử lớn hơn 0. Hành vi này không phải lúc nào cũng mong muốn, vì nó có thể dẫn đến kết quả không mong muốn và các lỗi khó theo dõi.
Một cách phổ biến để tránh những vấn đề này là tạo một bản sao của đối số trước khi sửa đổi nó. Ví dụ, mã sau sẽ không sửa đổi danh sách gốc:
def append_to_list(a_list:list, element:int):
if element > 0:
a_list = a_list + [element]
print ("Giá trị bên trong hàm: ", a_list)
a_list = [1, 2, 3]
append_to_list(a_list, 5)
print ("Giá trị bên ngoài hàm: ", a_list)
Kết quả
Giá trị bên trong hàm: [1, 2, 3, 5]
Giá trị bên ngoài hàm: [1, 2, 3]
Vấn đề tương tự xảy ra với từ điển và tập hợp.
def update_dictionary(a_dict, keyword, value):
a_dict[keyword] = value
print ("Giá trị bên trong hàm: ", a_dict)
a_dict = {"count": 1}
update_dictionary(a_dict, "message", "good")
print ("Giá trị bên ngoài hàm: ", a_dict)
Kết quả
Giá trị bên trong hàm: {'count': 1, 'message': 'good'}
Giá trị bên ngoài hàm: {'count': 1, 'message': 'good'}
Giải pháp
1. Tạo một bản sao của đối số khả biến trước khi sửa đổi nó
Ví dụ:
import copy
def update_list(a_list):
a_list_copy = copy.copy(a_list)
a_list_copy.append(4)
return a_list_copy
original_list = [1, 2, 3]
modified_list = update_list(original_list)
print(original_list)
print(modified_list)
Kết quả
[1, 2, 3]
[1, 2, 3, 4]
2. Sử dụng đối số bất biến thay vì đối số khả biến. Ví dụ: sử dụng thư viện như Frozen Dict để tạo một từ điển bất biến
from frozendict import frozendict
frozen_dict = frozendict({ 'hello': 'World' })
print(frozen_dict)
frozendict.frozendict({'hello': 'World'})
print(frozen_dict['hello'])
World
frozen_dict["another_key"] = "value"
nó gây ra ngoại lệ với TypeError
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
Cell In[44], line 1
----> 1 frozen_dict["another_key"] = "value"
File ~/.pyenv/versions/3.10.8/envs/glinteco-website/lib/python3.10/site-packages/frozendict/core.py:198, in frozendict.__setitem__(self, key, val, *args, **kwargs)
197 def __setitem__(self, key, val, *args, **kwargs):
--> 198 raise TypeError(
199 f"'{self.__class__.__name__}' object doesn't support item "
200 "assignment"
201 )
TypeError: 'frozendict' object doesn't support item assignment
Điều quan trọng là phải nhận thức được Đối số Khả Biến Python và cách chúng có thể ảnh hưởng đến hành vi của mã của bạn. Để tránh các tác dụng phụ không mong muốn, tốt nhất là sử dụng đối số bất biến thay thế. Đối số bất biến không thể được thay đổi bên trong hàm và được truyền theo giá trị thay vì theo tham chiếu.
Điều này có thể giúp việc gỡ lỗi dễ dàng hơn và giảm khả năng xảy ra hành vi không mong muốn.