- Lệnh switch truyền thống không tồn tại trong Python, nhưng nó có thể được mô phỏng hiệu quả bằng các điều kiện và từ điển.
- Bắt đầu từ Python 3.10, cấu trúc match-case mới mang lại sức mạnh và khả năng đọc tốt hơn bằng cách thay thế cấu trúc switch-case cổ điển.
- Nhiều kỹ thuật khác nhau cho phép bạn triển khai logic trắc nghiệm trong Python, phù hợp với nhiều tình huống và phiên bản ngôn ngữ khác nhau.
Bạn đã bao giờ tự hỏi làm thế nào để quản lý nhiều điều kiện trong Python một cách đơn giản và hiệu quả chưa? Khi làm việc với các ngôn ngữ như C, Java hoặc JavaScript, bạn có thể đã sử dụng câu lệnh switch-case quen thuộc để lựa chọn giữa nhiều tùy chọn dựa trên giá trị của một biến. Tuy nhiên, trong Python, cơ chế kinh điển này lại không tồn tại… cho đến gần đây. Mặc dù các nhà phát triển đã phải tìm kiếm các giải pháp thay thế trong nhiều năm, nhưng giờ đây ngôn ngữ này đã cung cấp một giải pháp hiện đại và mạnh mẽ.
Bài viết này là hướng dẫn toàn diện giúp bạn hiểu cách sử dụng từ khóa tương đương với `switch` trong Python , khám phá các lựa chọn thay thế mạnh mẽ hơn trong các phiên bản cũ hơn, làm rõ lý do tại sao nó không được đưa vào trong giai đoạn đầu và học cách viết mã sạch hơn, dễ đọc hơn, bất kể bạn sử dụng phiên bản nào. Hãy sẵn sàng để học tất cả các thủ thuật, ví dụ và sự khác biệt chính trong việc triển khai nhiều điều kiện trong hệ sinh thái Python.
Switch có tồn tại trong Python không? Lịch sử và lý do tại sao nó không tồn tại
Cú pháp switch-case, có mặt trong nhiều ngôn ngữ lập trình, mãi đến phiên bản 3.10 mới chính thức được đưa vào Python. Lý do chính là về mặt triết lý: những người sáng tạo ra Python luôn ưu tiên sự đơn giản và dễ đọc. Họ tin rằng việc giới thiệu một cú pháp mới cho câu lệnh switch có thể làm phức tạp mọi thứ, vì vậy if-elif-else là đủ để đáp ứng nhu cầu đó. Hơn nữa, chưa bao giờ có sự đồng thuận về cú pháp lý tưởng. Trên thực tế, một số đề xuất chính thức (PEP 275, PEP 3103) đã bị bác bỏ do thiếu sự đồng thuận và vì nhiều người cảm thấy rằng các phương án thay thế hiện có đã đủ rõ ràng và mạnh mẽ.
Trong nhiều năm, cộng đồng đã bù đắp cho sự thiếu vắng câu lệnh `switch` bằng cách sử dụng chuỗi điều kiện và từ điển. Không cần phải nói, điều này đã gây ra nhiều tranh luận, nhưng thay vì là một nhược điểm không thể vượt qua, những phương pháp này đã chứng tỏ tính linh hoạt và khả năng thích ứng cao. Tuy nhiên, khi các dự án trở nên phức tạp hơn, nhu cầu về một giải pháp thanh lịch hơn ngày càng trở nên rõ ràng.
Vỏ công tắc là gì và nó được sử dụng để làm gì?
Câu lệnh switch-case là một cấu trúc điều khiển được sử dụng trong nhiều ngôn ngữ lập trình để thực thi các khối mã khác nhau tùy thuộc vào giá trị của một biến hoặc biểu thức. Nói cách khác, nó cho phép bạn chọn một tùy chọn từ nhiều khả năng một cách rõ ràng và trực tiếp, tránh được các chuỗi câu lệnh điều kiện dài dòng.
Các ví dụ sử dụng điển hình sẽ là: hiển thị tên của một ngày trong tuần dựa trên một con số, chỉ định điểm, chọn các hoạt động dựa trên đầu vào của người dùng, v.v. Trong các ngôn ngữ như C hoặc Java, cú pháp của nó rất đơn giản:
switch(valor) {
case 1:
// acción
break;
case 2:
// otra acción
break;
default:
// acción por defecto
}
Trong Python, cấu trúc cổ điển này mới xuất hiện gần đây, do đó các nhà phát triển phải sáng tạo để đạt được kết quả tương tự.
Sự xuất hiện của lệnh switch trong Python: câu lệnh match-case (kể từ Python 3.10)
Với phiên bản 3.10, Python đã tích hợp một tính năng được mong chờ từ lâu: câu lệnh match-case. Mặc dù cú pháp của nó tương tự như câu lệnh switch-case truyền thống, nhưng thực tế nó mạnh mẽ hơn nhiều, vì nó giới thiệu tính năng so khớp mẫu , cho phép so sánh không chỉ các giá trị đơn giản mà còn cả các cấu trúc phức tạp, bộ dữ liệu, lớp, danh sách, từ điển, v.v.
Match-case của Python được viết như thế này:
def ejemplo_switch(x):
match x:
case 1:
return "uno"
case 2:
return "dos"
case _:
return "desconocido"
Dấu gạch dưới ( _ ) hoạt động như một ký tự đại diện và tương đương với ký tự mặc định trong các ngôn ngữ khác, được thực thi khi không có mẫu nào trước đó khớp.
Tại sao nó lại mạnh mẽ đến vậy? Bởi vì bạn có thể nhận các mẫu phức tạp, nắm bắt các biến, mở các bộ dữ liệu hoặc đối tượng, và thậm chí sử dụng các điều kiện bảo vệ để thêm các điều kiện bổ sung sau câu lệnh case:
match dato:
case (a, b) if a > b:
print("El primer elemento es mayor que el segundo")
case (a, b):
print(f"Valores: {a}, {b}")
Ngoài ra, trong Python 3.10 trở lên, cấu trúc này cải thiện khả năng đọc, khả năng bảo trì và khả năng mở rộng của mã, đặc biệt là khi xử lý nhiều trường hợp.
Các lựa chọn thay thế để chuyển đổi trong Python cho các phiên bản cũ hơn
Trước khi cú pháp match-case ra đời , các nhà phát triển đã nghĩ ra những phương án thay thế cũng hợp lệ không kém. Hai phương án phổ biến nhất là sử dụng chuỗi if-elif-else và ánh xạ từ điển . Chúng ta hãy cùng xem xét chi tiết từng phương án:
1. Sử dụng if-elif-else
Giải pháp trực tiếp và dễ nhất là sử dụng chuỗi điều kiện bằng cách dùng if, elif và else. Điều này cho phép bạn bao quát tất cả các giá trị có thể có của một biến và thực thi khối mã tương ứng. Ví dụ, để hiển thị ngày trong tuần dựa trên một số:
dia = 4
if dia == 1:
print('lunes')
elif dia == 2:
print('martes')
elif dia == 3:
print('miércoles')
elif dia == 4:
print('jueves')
elif dia == 5:
print('viernes')
elif dia == 6:
print('sábado')
elif dia == 7:
print('domingo')
else:
print('error')
Ưu điểm của cách tiếp cận này:
- Mã đơn giản và dễ đọc.
- Bạn không cần bất kỳ cấu trúc đặc biệt nào khác; đây là Python thuần túy.
- Có thể sử dụng bất kỳ loại so sánh nào, không chỉ có so sánh bằng.
Nhược điểm của thang if-elif-else:
- Có xu hướng lặp lại mã. Bạn phải lặp lại biến trong mỗi lần so sánh, điều này tạo ra rất nhiều văn bản không cần thiết nếu bạn có nhiều trường hợp.
- Ít hiệu quả hơn khi có nhiều điều kiện. Nếu vụ án đã ở giai đoạn cuối, tất cả các vụ án trước đó sẽ được đánh giá trước khi đến.
- Khó khăn khi thêm hoặc xóa các trường hợp một cách linh hoạt.
2. Sử dụng từ điển để mô phỏng trường hợp chuyển đổi
Một cách rất "Pythonic" để mô phỏng câu lệnh switch là sử dụng từ điển. Ý tưởng rất đơn giản: bạn liên kết mỗi giá trị (khóa) với hàm hoặc hành động tương ứng (giá trị). Sau đó, bạn truy vấn từ điển để lấy hàm và thực thi nó.
def lunes():
print('lunes')
def martes():
print('martes')
def error():
print('error')
switch_semana = {
1: lunes,
2: martes,
# ... otros días ...
}
dia = 8
switch_semana.get(dia, error)()
Ưu điểm của phương pháp này:
- Mã lệnh nhỏ gọn và dễ mở rộng.
- Truy cập vào chức năng phù hợp rất nhanh. Từ điển sử dụng hàm băm, do đó việc tìm kiếm diễn ra gần như ngay lập tức.
- Cho phép bạn gán cùng một chức năng cho nhiều phím (ví dụ: cho các trường hợp nhóm).
- Công tắc có thể được sửa đổi khi chạy.
Nhược điểm:
- Yêu cầu phải xác định trước tất cả các chức năng liên quan, điều này có thể gây phức tạp cho các hành động đơn giản.
- Nó chỉ cho phép so sánh để tìm sự bằng nhau (không áp dụng cho khoảng, phạm vi, v.v.).
- Nó không dành cho những trường hợp có logic điều kiện phức tạp hơn trong mỗi lựa chọn.
Sự khác biệt giữa if-elif-else và switch (hoặc match-case)
Cơ chế hoạt động bên trong của chuỗi if-elif-else khác với câu lệnh switch. Trong câu lệnh if-elif-else, các điều kiện được đánh giá từng cái một, từ trên xuống dưới, cho đến khi điều kiện đúng đầu tiên được thỏa mãn. Do đó, nếu giá trị mong muốn nằm ở đầu chuỗi, quá trình sẽ nhanh; nếu nó nằm ở cuối chuỗi, quá trình sẽ mất nhiều thời gian hơn.
Ngược lại, các câu lệnh switch truyền thống (và từ điển như một lựa chọn thay thế trong Python) thường sử dụng bảng tra cứu, dẫn đến việc truy cập đồng nhất hơn, bất kể số lượng trường hợp hay vị trí của chúng. Với các câu lệnh match-case và từ điển, thời gian truy cập sẽ nhất quán hơn nhiều.
Khi nào nên chọn phương án thay thế?
Không có giải pháp chung duy nhất; công cụ tốt nhất phụ thuộc vào vấn đề cụ thể.
- Đối với số lượng điều kiện nhỏ hoặc logic phức tạp trong mỗi nhánh, if-elif-else là lựa chọn đơn giản nhất. Nó cho phép so sánh và rất linh hoạt.
- Khi bạn có nhiều trường hợp và mỗi trường hợp chỉ thực hiện một hành động cụ thể, hãy dựa vào từ điển. Mã sạch hơn, có khả năng mở rộng và dễ bảo trì hơn.
- Nếu bạn sử dụng Python 3.10 hoặc cao hơn, trường hợp phù hợp Đây là lựa chọn tốt nhất về độ rõ nét và sức mạnh. Nó cho phép bạn kết hợp sự thanh lịch của công tắc với sức mạnh của việc khớp mẫu trên các cấu trúc phức tạp.
Luôn nghĩ về khả năng đọc, hiệu suất và khả năng bảo trì của mã của bạn.
Ví dụ thực tế về việc sử dụng switch trong Python và các giải pháp thay thế
Hãy cùng xem xét một số ví dụ trong đó mỗi giải pháp thay thế này được áp dụng, từ mức độ phức tạp ít nhất đến cao nhất:
Ví dụ 1: Tính điểm dựa trên điểm số
# Usando if-elif-else
puntuacion = 85
if puntuacion >= 90:
print('Sobresaliente')
elif puntuacion >= 80:
print('Notable')
elif puntuacion >= 70:
print('Bien')
else:
print('Insuficiente')
Trường hợp này hoàn hảo để sử dụng câu điều kiện, vì bạn đang làm việc với khoảng thời gian chứ không phải giá trị cố định.
Ví dụ 2: Hiển thị ngày trong tuần theo số (có từ điển)
# Definición de funciones para cada día
def lunes():
print('lunes')
def martes():
print('martes')
def miercoles():
print('miércoles')
def jueves():
print('jueves')
def viernes():
print('viernes')
def sabado():
print('sábado')
def domingo():
print('domingo')
def error():
print('error')
switch_semana = {
1: lunes,
2: martes,
3: miercoles,
4: jueves,
5: viernes,
6: sabado,
7: domingo
}
dia = 8
switch_semana.get(dia, error)()
Ví dụ 3: Sử dụng match-case để chọn phép toán số học
operacion = 'suma'
a = 10
b = 5
match operacion:
case 'suma':
print(a + b)
case 'resta':
print(a - b)
case 'multiplicacion':
print(a * b)
case 'division':
print(a / b)
case _:
print('Operación no válida')
Như bạn thấy, cú pháp rất đơn giản và rõ ràng. Dấu gạch dưới chỉ ra trường hợp mặc định.
Ví dụ nâng cao: khớp mẫu với match-case
Ưu điểm vượt trội của phân tích so khớp trường hợp nằm ở khả năng xử lý các mẫu phức tạp. Ví dụ, bạn có thể phân tích các bộ dữ liệu (tuple), danh sách (list), từ điển (dictionary), đối tượng, v.v.
punto = (3, 5)
match punto:
case (0, 0):
print('Origen')
case (0, y):
print(f'Eje Y en {y}')
case (x, 0):
print(f'Eje X en {x}')
case (x, y):
print(f'Coordenadas X={x}, Y={y}')
Bạn thậm chí có thể sử dụng mệnh đề if (điều kiện kiểm tra) để thêm các điều kiện bổ sung cho từng trường hợp.
Sự khác biệt về hiệu suất giữa if-elif-else, từ điển và match-case
Trong hầu hết các trường hợp, sự khác biệt về hiệu năng là không đáng kể đối với các đoạn mã thông thường. Tuy nhiên, khi có nhiều lựa chọn thay thế, từ điển và các đối số so khớp có thể hiệu quả hơn, vì chúng giảm số lượng phép so sánh. Trong mọi trường hợp, yếu tố quan trọng nhất thường là khả năng đọc hiểu và bảo trì mã , chứ không phải là những tối ưu hóa nhỏ hiếm khi tạo ra sự khác biệt trong các dự án thực tế.
Sử dụng kỹ thuật giúp mã rõ ràng hơn và tránh lỗi.
Giải pháp sáng tạo: các lớp và trình quản lý ngữ cảnh để mô phỏng chuyển đổi
Một số nhà phát triển đã tạo ra các lớp chuyên dụng cho phép mô phỏng hành vi cổ điển của câu lệnh switch, bao gồm các tùy chọn nâng cao như thêm lệnh break để kiểm soát việc thực thi các trường hợp tiếp theo, nhóm các trường hợp, tùy chỉnh các phép so sánh hoặc kích hoạt chế độ nghiêm ngặt đảm bảo chỉ có một nhánh được thực thi.
Ví dụ, một trình quản lý ngữ cảnh tùy chỉnh có thể được triển khai để sử dụng cú pháp rất giống với các ngôn ngữ khác:
class switch:
def __init__(self, variable, comparator=None, strict=False):
self.variable = variable
self.matched = False
self.matching = False
if comparator:
self.comparator = comparator
else:
self.comparator = lambda x, y: x == y
self.strict = strict
def __enter__(self):
return self
def __exit__(self, exc_type, exc_val, exc_tb):
pass
def case(self, expr, break_=False):
if self.strict:
if self.matched:
return False
if self.matching or self.comparator(self.variable, expr):
if not break_:
self.matching = True
else:
self.matched = True
self.matching = False
return True
else:
return False
else:
if self.matching or self.comparator(self.variable, expr):
if not break_:
self.matching = True
else:
self.matched = True
self.matching = False
return True
else:
return False
def default(self):
return not self.matched and not self.matching
Sử dụng lớp này cho phép sử dụng cú pháp như sau:
dia = 4
with switch(dia) as s:
if s.case(1, True): print('lunes')
if s.case(2, True): print('martes')
if s.case(3, True): print('miércoles')
if s.case(4, True): print('jueves')
if s.case(5, True): print('viernes')
if s.case(6, True): print('sábado')
if s.case(7, True): print('domingo')
if s.default(): print('error')
Giải pháp này có những ưu điểm gì? Nó có cú pháp rất quen thuộc với những người đến từ các ngôn ngữ khác và cho phép tùy chỉnh nâng cao, chẳng hạn như sử dụng bất kỳ hàm so sánh nào, nhóm các trường hợp, thực thi nhiều nhánh hoặc chỉ một nhánh, v.v. Nhược điểm là nó có xu hướng chậm hơn và yêu cầu nhập hoặc định nghĩa lớp đặc biệt.
Sử dụng hàm lambda để đơn giản hóa các hành động trên từ điển
Thông thường bạn không cần phải định nghĩa các hàm riêng biệt cho mỗi hành động; bạn có thể sử dụng các hàm ẩn danh (lambda). Điều này đặc biệt hữu ích khi hành động cần thực hiện rất đơn giản:
switch_operaciones = {
'sumar': lambda a, b: a + b,
'restar': lambda a, b: a - b,
'multiplicar': lambda a, b: a * b
}
operacion = 'sumar'
resultado = switch_operaciones.get(operacion, lambda a, b: None)(5, 3)
print(resultado)
Điều này làm cho mã trở nên gọn nhẹ và dễ mở rộng mà không làm mất đi tính rõ ràng.
Các trường hợp sử dụng nâng cao: So khớp mẫu trong Match-Case
Câu lệnh `match-case` của Python 3.10 không chỉ đơn thuần sao chép câu lệnh `switch-case` kinh điển. Sức mạnh thực sự của nó nằm ở khả năng khớp các mẫu cấu trúc . Ví dụ, nó cho phép bạn dễ dàng phân biệt giữa các cấu trúc dữ liệu khác nhau, các lớp tùy chỉnh, phân tách đối tượng và nắm bắt các phần tử con.
Ví dụ với danh sách và bộ:
datos =
match datos:
case :
print('Lista con 1, 2, 3')
case :
print('Lista que empieza con 1')
case _:
print('Otra lista')
Ví dụ với các đối tượng (giả sử là lớp Point):
class Punto:
def __init__(self, x, y):
self.x = x
self.y = y
p = Punto(2, 3)
match p:
case Punto(x=0, y=0):
print('Origen')
case Punto(x, y):
print(f'Coordenadas: {x} {y}')
Cơ chế này cho phép bạn viết mã có khả năng biểu đạt cao, thích ứng với các cấu trúc phức tạp mà không làm mất đi khả năng đọc.
Các khía cạnh cần xem xét khi di chuyển mã: khả năng tương thích và các biện pháp thực hành tốt nhất
Không phải dự án nào cũng có thể sử dụng match-case ngay lập tức. Nếu bạn đang làm việc trong môi trường với các phiên bản Python cũ hơn (ví dụ: 3.8 hoặc 3.9), bạn sẽ phải chọn sử dụng từ điển. Khi có thể nâng cấp lên phiên bản 3.10 trở lên, hãy tận dụng sức mạnh và sự rõ ràng của khớp mẫu, đặc biệt là trong các dự án cần logic lựa chọn nhiều.
Ghi nhớ:
- Chọn tùy chọn cung cấp khả năng đọc, tính linh hoạt và dễ bảo trì tốt nhất.
- Trong những bài toán rất đơn giản (một vài trường hợp), if-elif-else thường đủ và trực tiếp hơn.
- Đối với các bảng lựa chọn lớn, hãy sử dụng từ điển và hàm.
- Đối với các cấu trúc phức tạp hoặc để tận dụng tối đa Python hiện đại, hãy chọn match-case.
Một mẹo nhỏ: bạn có thể chuyển đổi các hàm hiện có để chấp nhận từ điển hành động, giúp việc chuyển đổi giữa các phương pháp trở nên dễ dàng hơn.
Mẹo tối ưu hóa và thiết kế để có mã Python sạch hơn
Đừng mắc bẫy thiết kế những chuỗi điều kiện dài vô tận chỉ để bắt chước câu lệnh switch kinh điển. Hãy suy nghĩ về từng trường hợp cụ thể và đánh giá xem cấu trúc điều khiển nào mang lại giá trị cao nhất cho ngữ cảnh chương trình của bạn. Hãy nhớ rằng Python coi trọng sự rõ ràng, vì vậy hãy tránh làm phức tạp mã của bạn nếu bạn có thể đạt được kết quả tương tự một cách đơn giản.
Một mẹo quan trọng: Khi sử dụng từ điển, hãy sử dụng chức năng get() để tránh lỗi nếu khóa không tồn tại và do đó có thể xác định trường hợp mặc định một cách khéo léo.
So sánh với các ngôn ngữ khác và suy nghĩ cuối cùng
Trong một số ngôn ngữ, chẳng hạn như C, C++ hoặc Java, các lệnh chuyển đổi chỉ cho phép so sánh các giá trị đơn giản (số nguyên, chuỗi) và cung cấp ít giá trị cho các cấu trúc phức tạp. Python tiến xa hơn một bước: đầu tiên, nó cung cấp các giải pháp thay thế đa năng (if-elif-else, từ điển) và giờ đây nó mở ra cánh cửa cho logic nâng cao mà không cần nỗ lực thêm. Điều quan trọng là tận dụng lợi thế của từng phiên bản và không ép buộc bản thân bắt chước các cú pháp khác nếu vấn đề đòi hỏi một giải pháp khác.
Nếu bạn mới bắt đầu với Python hoặc đến từ ngôn ngữ khác, đừng nản lòng nếu bạn không tìm thấy từ khóa switch trong hướng dẫn. Hãy nghĩ về tất cả các khả năng có sẵn và chọn khả năng phù hợp nhất với ngữ cảnh và nhu cầu của bạn.
Quản lý nhiều phương án thay thế trong Python chưa bao giờ dễ dàng hoặc mạnh mẽ hơn thế. Bây giờ bạn đã hiểu lý do đằng sau sự vắng mặt (và sự xuất hiện sau đó) của switch, cách mô phỏng nó hiệu quả trong bất kỳ phiên bản nào và cách tận dụng tối đa câu lệnh match-case mới. Cho dù bạn phải lựa chọn giữa nửa tá tùy chọn, thao tác các cấu trúc phức tạp, tuân theo các phương pháp hay nhất hay lo lắng về hiệu suất, bạn đều có các phương án thay thế mạnh mẽ, thanh lịch và linh hoạt. Cho dù mã của bạn dành cho các tập lệnh nhanh hay các ứng dụng phức tạp, Python đều cung cấp cho bạn các công cụ để viết mã rõ ràng, nhanh chóng và dễ dàng.