a

Câu hỏi Python có một toán tử điều kiện bậc ba không?


Nếu Python không có toán tử điều kiện bậc ba, có thể mô phỏng một toán tử bằng cách sử dụng các cấu trúc ngôn ngữ khác không?


4442


gốc


Mặc dù Pythons lớn hơn 2,5 đang dần trôi dạt vào lịch sử, đây là danh sách các thủ thuật điều hành cũ của 2.5 tuổi: "Thành ngữ Python", tìm kiếm cụm từ 'Biểu thức có điều kiện' . Wikipedia cũng khá hữu ích Ж :-) - ジョージ
Trong tài liệu chính thức của Python 3.0 được tham chiếu trong một chú thích ở trên, điều này được gọi là "conditional_expressions" và được định nghĩa rất khó hiểu. Tài liệu đó thậm chí không bao gồm thuật ngữ "ternary", vì vậy bạn sẽ khó có thể tìm thấy nó thông qua Google trừ khi bạn biết chính xác những gì cần tìm. Các tài liệu phiên bản 2 có phần hữu ích hơn và bao gồm một liên kết đến "PEP 308", bao gồm rất nhiều bối cảnh lịch sử thú vị liên quan đến câu hỏi này. - nobar
"ternary" (có ba đầu vào) là một thuộc tính hậu quả của sự tăng tốc này, không phải là một thuộc tính xác định của khái niệm. ví dụ: SQL có case [...] { when ... then ...} [ else ... ] end cho một hiệu ứng tương tự nhưng không phải ở tất cả ba. - user313114
cũng ISO / IEC 9899 (tiêu chuẩn ngôn ngữ lập trình C) phần 6.5.15 gọi nó là "toán tử điều kiện" - user313114
Wikipedia đề cập đến điều này một cách kỹ lưỡng trong bài báo "?:". - HelloGoodbye


Các câu trả lời:


Đúng thêm trong phiên bản 2.5.
Cú pháp là:

a if condition else b

Đầu tiên condition được đánh giá, sau đó a hoặc là b được trả lại dựa trên Boolean giá trị của condition
Nếu condition đánh giá Thật  a được trả lại, khác b Được trả lại.

Ví dụ:

>>> 'true' if True else 'false'
'true'
>>> 'true' if False else 'false'
'false'

Lưu ý rằng điều kiện là một biểu hiện, không phải tuyên bố. Điều này có nghĩa là bạn không thể sử dụng bài tập hoặc pass hoặc các phát biểu khác trong điều kiện:

>>> pass if False else x = 3
  File "<stdin>", line 1
    pass if False else x = 3
          ^
SyntaxError: invalid syntax

Trong trường hợp này, bạn phải sử dụng bình thường if tuyên bố thay vì một điều kiện.


Hãy nhớ rằng nó bị cau mày bởi một số Pythonistas vì nhiều lý do:

  • Thứ tự của các đối số khác với nhiều ngôn ngữ khác (như C, Ruby, Java, v.v.), có thể dẫn đến lỗi khi mọi người không quen với hành vi "đáng ngạc nhiên" của Python sử dụng nó (họ có thể đảo ngược thứ tự).
  • Một số tìm thấy nó "khó sử dụng", vì nó đi ngược lại với dòng chảy bình thường của suy nghĩ (suy nghĩ về điều kiện đầu tiên và sau đó các hiệu ứng).
  • Lý do phong cách.

Nếu bạn gặp khó khăn khi nhớ thứ tự, hãy nhớ rằng nếu bạn đọc to, bạn (gần như) nói những gì bạn muốn nói. Ví dụ, x = 4 if b > 8 else 9 được đọc to như x will be 4 if b is greater than 8 otherwise 9.

Tài liệu chính thức:


5299



Đơn đặt hàng có vẻ lạ đối với người lập trình f(x) = |x| = x if x > 0 else -x âm thanh rất tự nhiên đối với các nhà toán học. Bạn cũng có thể hiểu nó như là A trong hầu hết trường hợp, ngoại trừ khi C thì bạn nên làm B thay vào đó ... - yota
Hãy cẩn thận với thứ tự của các hoạt động khi sử dụng này. Ví dụ, dòng z = 3 + x if x < y else y. Nếu x=2 và y=1, bạn có thể mong đợi rằng để mang lại 4, nhưng nó thực sự sẽ mang lại 1. z = 3 + (x if x > y else y) là cách sử dụng đúng. - Kal Zekdor
Vấn đề là nếu bạn muốn thực hiện các đánh giá bổ sung sau điều kiện được đánh giá, như thêm giá trị vào kết quả, bạn sẽ cần thêm biểu thức bổ sung cho cả hai bên (z = 3 + x if x < y else 3 + y), hoặc nhóm các điều kiện (z = 3 + (x if x < y else y) hoặc là z = (x if x < y else y) + 3) - Kal Zekdor
@Pred try print("OK" if status else "NOT OK") - BusyAnt
Tôi thích sự mỉa mai mơ hồ của cú pháp này, thứ tự được mô tả là tự nhiên bởi một người được gọi là @yota. - nickf


Bạn có thể lập chỉ mục thành một bộ dữ liệu:

(falseValue, trueValue)[test]

test cần trả lại Thật hoặc là Sai.
Nó có thể an toàn hơn để luôn thực hiện nó như:

(falseValue, trueValue)[test == True]

hoặc bạn có thể sử dụng tích hợp sẵn bool() để đảm bảo Boolean giá trị:

(falseValue, trueValue)[bool(<expression>)]

594



Lưu ý rằng điều này luôn luôn đánh giá tất cả mọi thứ, trong khi if / else xây dựng chỉ đánh giá biểu thức chiến thắng. - SilverbackNet
(lambda: print("a"), lambda: print("b"))[test==true]() - Dustin Getz
Cần lưu ý rằng những gì trong []s có thể là một biểu thức tùy ý. Ngoài ra, vì sự an toàn, bạn có thể kiểm tra một cách rõ ràng sự thật bằng cách viết [bool(<expression>)]. Các bool() chức năng đã được khoảng từ v2.2.1. - martineau
Điều này là rất tốt cho mã-golf, không quá nhiều cho mã thực tế. Mặc dù tôi đã quen với việc sử dụng nó, đôi khi tôi sử dụng nó đôi khi cho sự conciseness khi làm một cái gì đó rõ ràng như chọn giữa hai hằng số chuỗi. - Claudiu
Tôi đã thực hiện một mẹo tương tự - chỉ một hoặc hai lần, nhưng đã thực hiện nó - bằng cách lập chỉ mục vào một từ điển với True và False như các phím: {True:trueValue, False:falseValue}[test]  Tôi không biết liệu điều này có kém hiệu quả hay không, nhưng ít nhất nó cũng tránh được toàn bộ cuộc tranh luận "thanh lịch" và "xấu xí". Không có sự mơ hồ mà bạn đang đối phó với một boolean chứ không phải là một int. - JDM


Đối với các phiên bản trước 2.5, có mẹo:

[expression] and [on_true] or [on_false]

Nó có thể cho kết quả sai khi on_true   có giá trị boolean sai.1
Mặc dù nó có lợi ích của việc đánh giá các biểu thức từ trái sang phải, điều này rõ ràng hơn trong quan điểm của tôi.

1. Có tương đương với toán tử ternary "?"?


246



Biện pháp khắc phục là sử dụng (kiểm tra và [true_value] hoặc [false_value]) [0], để tránh bẫy này. - ThomasH
Toán tử bậc ba thường thực hiện nhanh hơn (đôi khi bằng 10-25%). - volcano
@volcano Bạn có nguồn cho tôi không? - OrangeTux
@OrangeTux Đây là mã đã tháo rời. Sử dụng phương pháp mà ThomasH đề xuất sẽ chậm hơn. - mbomb007


expression1 nếu điều kiện khác expression2

>>> a = 1
>>> b = 2
>>> 1 if a > b else -1 
-1
>>> 1 if a > b else -1 if a < b else 0
-1

157



Sự khác biệt giữa câu trả lời này và câu trả lời hàng đầu là gì? - kennytm
Điều này nhấn mạnh ý định chính của toán tử ternary: selection value. Nó cũng cho thấy rằng nhiều hơn một ternary có thể được xích lại với nhau thành một biểu thức duy nhất. - Roy Tinker
@Craig, tôi đồng ý, nhưng nó cũng hữu ích để biết những gì sẽ xảy ra khi không có dấu ngoặc đơn. Trong thực tế mã, tôi cũng sẽ có xu hướng chèn parens rõ ràng. - Jon Coombs
Bằng cách nào đó, tôi có thể hiểu điều này tốt hơn câu trả lời hàng đầu. - abhi divekar


Từ tài liệu:

Các biểu thức điều kiện (đôi khi được gọi là "toán tử bậc ba") có mức ưu tiên thấp nhất trong tất cả các phép toán Python.

Cách diễn đạt x if C else y đầu tiên đánh giá điều kiện, C (không phải x); nếu C là đúng, x được đánh giá và giá trị của nó được trả về; nếu không thì, y được đánh giá và giá trị của nó được trả về.

Xem PEP 308 để biết thêm chi tiết về các biểu thức có điều kiện.

Mới kể từ phiên bản 2.5.


106





Một toán tử cho một biểu thức có điều kiện trong Python đã được thêm vào năm 2006 như là một phần của Đề xuất tăng cường Python 308. Hình dạng của nó khác với chung ?: nhà điều hành và đó là:

<expression1> if <condition> else <expression2>

tương đương với:

if <condition>: <expression1> else: <expression2>

Đây là một ví dụ:

result = x if a > b else y

Một cú pháp khác có thể được sử dụng (tương thích với các phiên bản trước 2.5):

result = (lambda:y, lambda:x)[a > b]()

nơi toán hạng là đánh giá uể oải.

Một cách khác là bằng cách lập chỉ mục một bộ tuple (không phù hợp với toán tử điều kiện của hầu hết các ngôn ngữ khác):

result = (y, x)[a > b]

hoặc từ điển được xây dựng rõ ràng:

result = {True: x, False: y}[a > b]

Phương pháp khác (ít đáng tin cậy hơn), nhưng đơn giản hơn là sử dụng and và or toán tử:

result = (a > b) and x or y

tuy nhiên điều này sẽ không hiệu quả nếu x sẽ là False.

Cách giải quyết có thể là để thực hiện x và y danh sách hoặc bộ dữ liệu như sau:

result = ((a > b) and [x] or [y])[0]

hoặc là:

result = ((a > b) and (x,) or (y,))[0]

Nếu bạn đang làm việc với các từ điển, thay vì sử dụng một điều kiện bậc ba, bạn có thể tận dụng get(key, default), ví dụ:

shell = os.environ.get('SHELL', "/bin/sh")

Nguồn: ?: bằng Python tại Wikipedia


79





@lên:

thật không may

(falseValue, trueValue)[test]

giải pháp không có hành vi ngắn mạch; do đó cả falseValue và trueValue được đánh giá bất kể điều kiện. Điều này có thể kém tối ưu hoặc thậm chí là lỗi (tức là cả trueValue và falseValue đều có thể là phương thức và có tác dụng phụ).

Một giải pháp cho điều này sẽ là

(lambda: falseValue, lambda: trueValue)[test]()

(thực hiện trì hoãn cho đến khi người chiến thắng được biết đến)), nhưng nó giới thiệu sự không thống nhất giữa các đối tượng có thể gọi và không thể gọi được. Ngoài ra, nó không giải quyết trường hợp khi sử dụng các thuộc tính.

Và vì vậy câu chuyện đi - lựa chọn giữa 3 giải pháp được đề cập là một sự cân bằng giữa tính năng ngắn mạch, sử dụng ít nhất python 2.5 (IMHO không phải là vấn đề nữa) và không dễ bị "trueValue-evaluates-to-false" lỗi.


72





Đối với Python 2.5 và mới hơn, có một cú pháp cụ thể:

[on_true] if [cond] else [on_false]

Trong Pythons cũ, một toán tử bậc ba không được triển khai nhưng có thể mô phỏng nó.

cond and on_true or on_false

Mặc dù, có một vấn đề tiềm năng, nếu cond đánh giá True và on_true đánh giá False sau đó on_false được trả lại thay vì on_true. Nếu bạn muốn hành vi này, phương thức là OK, nếu không thì hãy sử dụng phương thức này:

{True: on_true, False: on_false}[cond is True] # is True, not == True

có thể được bao bọc bởi:

def q(cond, on_true, on_false)
    return {True: on_true, False: on_false}[cond is True]

và sử dụng cách này:

q(cond, on_true, on_false)

Nó tương thích với tất cả các phiên bản Python.


48



Hành vi không giống nhau - q("blob", on_true, on_false) trả về on_false, trong khi on_true if cond else on_false trả về on_true. Giải pháp thay thế là thay thế cond với cond is not None trong những trường hợp này, mặc dù đó không phải là một giải pháp hoàn hảo.
Tại sao không bool(cond) thay vì cond is True? Cựu kiểm tra tính trung thực của cond, sau này kiểm tra con trỏ-bình đẳng với True vật. Được đánh dấu bởi @AndrewCecil, "blob" là sự thật nhưng nó is not True. - Jonas Kölker
Wow, trông thật sự rất đáng sợ! :) Về mặt kỹ thuật, bạn thậm chí có thể viết [on_false, on_True][cond is True] vì vậy biểu thức trở nên ngắn hơn. - Arseny


Ternary Operator trong các ngôn ngữ lập trình khác nhau

Ở đây tôi chỉ cố gắng thể hiện một số khác biệt quan trọng trong ternary operator giữa một vài ngôn ngữ lập trình.

Toán tử Ternary trong Javascript

var a = true ? 1 : 0;
# 1
var b = false ? 1 : 0;
# 0

Toán tử Ternary trong Ruby

a = true ? 1 : 0
# 1
b = false ? 1 : 0
# 0

Toán tử ba năm ở Scala

val a = true ? 1 | 0
# 1
val b = false ? 1 | 0
# 0

Toán tử bậc ba trong lập trình R

a <- if (TRUE) 1 else 0
# 1
b <- if (FALSE) 1 else 0
# 0

Toán tử bậc ba trong Python

a = 1 if True else 0
# 1
b = 1 if False else 0
# 0

Bây giờ bạn có thể thấy vẻ đẹp của ngôn ngữ python. của nó rất dễ đọc và duy trì.


39



Điều này blogger tìm thấy toán tử ternary của python không nhất thiết khác với hầu hết các ngôn ngữ khác. - JamesThomasMoon1979
Ruby cũng làm việc với a = true ? 1 : 0 - rneves
"Bây giờ bạn có thể thấy vẻ đẹp của ngôn ngữ python. Nó rất dễ đọc và dễ bảo trì." Tôi không thấy sự liên quan của câu này, cũng không phải cách cú pháp toán tử ternary biểu diễn nó. - DaveMongoose
Nghe có vẻ có ý kiến; nhưng về cơ bản nó nói rằng cú pháp Python có thể được hiểu bởi một người không bao giờ nhìn thấy một toán tử bậc ba, trong khi rất ít người sẽ hiểu cú pháp thông thường hơn trừ khi họ được thông báo trước ý nghĩa của nó. - fralau
Algol68: a = .if. .thật. .sau đó. 1. 0 .fi. Điều này có thể được thể hiện cũng a = (. True. | 1 | 0) Như thường lệ Algol68 là một sự cải tiến so với người kế nhiệm của nó. - Albert van der Horst


Bạn thường có thể tìm thấy

cond and on_true or on_false

nhưng điều này dẫn đến vấn đề khi on_true == 0

>>> x = 0
>>> print x == 0 and 0 or 1 
1
>>> x = 1
>>> print x == 0 and 0 or 1 
1

nơi bạn mong đợi cho một toán tử ternary bình thường kết quả này

>>> x = 0
>>> print 0 if x == 0 else 1 
0
>>> x = 1
>>> print 0 if x == 0 else 1 
1

31