Trong Python, tôi nên kiểm tra xem một biến là Không, Đúng hay Sai


146

Tôi có một chức năng có thể trả về một trong ba điều sau:

  • thành công ( True)
  • thất bại ( False)
  • lỗi đọc / phân tích luồng ( None)

Câu hỏi của tôi là, nếu tôi không được phép kiểm tra lại Truehoặc False, tôi nên xem kết quả như thế nào. Dưới đây là cách tôi hiện đang làm:

result = simulate(open("myfile"))
if result == None:
    print "error parsing stream"
elif result == True: # shouldn't do this
    print "result pass"
else:
    print "result fail"

Là nó thực sự đơn giản như loại bỏ == Truemột phần hoặc tôi nên thêm một kiểu dữ liệu tri-bool. Tôi không muốn simulatehàm ném ngoại lệ vì tất cả những gì tôi muốn chương trình bên ngoài xảy ra với lỗi là ghi nhật ký và tiếp tục.


Bạn đang hỏi sai câu hỏi; bạn nên yêu cầu trợ giúp xác định kết quả của mình ... sự khác biệt mà bạn cảm nhận được giữa "lỗi" và "luồng phân tích lỗi", ý nghĩa của chúng là gì, hậu quả là gì, người gọi có thể muốn thực hiện hành động nào trong từng trường hợp (vượt qua, thất bại, lỗi phân tích cú pháp)?
John Machin

Tôi đang mô phỏng một hệ thống năng lượng điện, nếu mọi người mất điện vào nhà thì đó là một sự thất bại. Nếu tôi không thể đọc tệp mô phỏng thì đó là lỗi thuộc loại hoàn toàn khác.
James Brooks

2
Bên trong simulatechức năng tôi bắt tất cả các ngoại lệ; Tôi không muốn bất cứ điều gì xảy ra bên trong trình giả lập để dừng phần còn lại của chương trình đang chạy (và xử lý phần tử tiếp theo). Nhưng những câu trả lời đang khiến tôi thay đổi suy nghĩ.
James Brooks

1
@James Brooks: Phải. Đó là những gì cố gắng / ngoại trừ xử lý là tất cả về. Nếu bạn simulatecó những thứ nó có thể bắt và thử lại, điều đó thật tốt. Nhưng nếu nó "thất bại", nó sẽ không trở lại None. Nó chỉ nên đưa ra một ngoại lệ cho kịch bản gọi nó. Dù bằng cách nào, đã simulatexong. Trả về Nonekhông hữu ích như đưa ra một ngoại lệ thích hợp - hoặc cho phép một ngoại lệ truyền qua simulatetập lệnh gọi để xử lý.
S.Lott

1
@James, sử dụng except Exception:thay thế. Điều này bắt tất cả các lỗi "thực", cùng với WarningStopIteration. Nó cho phép KeyboardInterruptSystemExitthông qua mặc dù. Nếu bạn thực sự muốn bắt chúng, có lẽ tốt nhất là sử dụng một cấu trúc khác, ngoại trừ hoặc một số cấu trúc khác có ghi rõ ý định của bạn, vì đó không phải là "lỗi". (Nhưng tôi đã nói "hầu như không bao giờ" ... có lẽ trong trường hợp của bạn, bạn thực sự muốn lấy tất cả mọi thứ, và thậm chí ngăn Ctrl-C hoặc sys.exit()thoát ra, v.v.)
Peter Hansen

Câu trả lời:


119

Đừng sợ ngoại lệ! Có chương trình của bạn chỉ cần đăng nhập và tiếp tục dễ dàng như:

try:
    result = simulate(open("myfile"))
except SimulationException as sim_exc:
    print "error parsing stream", sim_exc
else:
    if result:
        print "result pass"
    else:
        print "result fail"

# execution continues from here, regardless of exception or not

Và bây giờ bạn có thể có một loại thông báo phong phú hơn nhiều từ phương thức mô phỏng như chính xác những gì đã sai, trong trường hợp bạn thấy lỗi / không có lỗi không đủ thông tin.


Đã đồng ý. Pythonic nhiều hơn so với giải pháp rõ ràng phổ biến hơn ở trên (có mùi quá giống mã C).
Brandon

7
@Brandon Không đồng ý. Mã này dài hơn và tệ hơn, ít đọc hơn giải pháp ở trên (hoặc phiên bản cải tiến bên dưới): nhiều vết lõm hơn, các câu lệnh khác nhau hơn - đoán tại sao cái sau lại phổ biến hơn, như bạn nói ... ;-) Tại sao cố gắng trở thành 'Pythonic' nếu điều đó dẫn đến mã khó xử hơn ...?
Rolf Bartstra

Bây giờ hãy in dấu vết thay vì "luồng phân tích lỗi" và bạn đã nhận được phiếu bầu của tôi.
CivilFan

Ok, dù sao bạn cũng đã nhận được phiếu bầu của tôi, nhưng ý tôi là in một cái gì đó như thế traceback.format_exc() . Xem câu trả lời SO này.
CivilFan

10
Nhiều người sẽ đến trang này để tìm câu trả lời cho câu hỏi tiêu đề. Đối với hầu hết chúng ta "Đừng sợ Ngoại lệ!" không có gì để làm với tình hình của chúng tôi. Chúng ta chỉ cần kiểm tra Đúng, Sai và Không. Mặc dù một số trường hợp thay thế được đề xuất của bạn là hợp lệ đối với một số trường hợp, tôi nghĩ tốt nhất là bao gồm một câu trả lời cho câu hỏi như đã hỏi.
differlysuperiorman

161
if result is None:
    print "error parsing stream"
elif result:
    print "result pass"
else:
    print "result fail"

giữ cho nó đơn giản và rõ ràng. Tất nhiên bạn có thể xác định trước một từ điển.

messages = {None: 'error', True: 'pass', False: 'fail'}
print messages[result]

Nếu bạn có kế hoạch sửa đổi simulatechức năng của mình để bao gồm nhiều mã trả về hơn, việc duy trì mã này có thể trở thành một vấn đề.

Điều này simulatecũng có thể gây ra một ngoại lệ đối với lỗi phân tích cú pháp, trong trường hợp đó, bạn sẽ bắt nó ở đây hoặc để nó lan truyền lên cấp và bit in sẽ được giảm xuống thành một câu lệnh if-other.


1
Cái sau là một thử nghiệm rõ ràng chống lại Đúng hay Sai, phải không?
Peter Eisentraut

1
tất nhiên, nhưng biết rằng đây chỉ là những giá trị trả về có thể, tôi không nghĩ đó là vấn đề.
SilentGhost

và nó dường như cũng nhanh hơn một chút
SilentGhost

a = 'foo' nếu a: in 'đúng' a không thực sự ĐÚNG, nó không phải là không có
wesm

17

Không bao giờ, không bao giờ, không bao giờ nói

if something == True:

Không bao giờ. Thật điên rồ, vì bạn đang lặp đi lặp lại một cách thừa thãi những gì được chỉ định thừa là quy tắc điều kiện dự phòng cho câu lệnh if.

Tệ hơn, vẫn, không bao giờ, không bao giờ, không bao giờ nói

if something == False:

Bạn có not. Hãy sử dụng nó.

Cuối cùng, làm a == Nonelà không hiệu quả. Làm a is None. Nonelà một đối tượng singleton đặc biệt, chỉ có thể có một. Chỉ cần kiểm tra xem bạn có đối tượng đó không.


3
Kiểm tra sự bằng nhau Truekhông phải là dư thừa (mặc dù tôi đồng ý rằng nó không hợp lý). Nó có thể gọi một __eq__phương pháp đặc biệt khác, thực tế có thể làm bất cứ điều gì.
Scott Griffiths

5
@Scott Griffiths: Điểm tốt. Đó là một kịch bản thực sự và sâu sắc kinh hoàng. Nếu đó thực sự là trường hợp, chương trình vi phạm những kỳ vọng cơ bản của chúng tôi theo cách khiến nó trở thành thứ gì đó đơn giản cần được xóa và viết lại từ đầu mà không có phép thuật đen như vậy.
S.Lott

78
'Không bao giờ không bao giờ không bao giờ' ...? Có những trường hợp mặc dù if something == Truemang lại một kết quả khác so với if something, ví dụ như đối với người không boolean something. 2==Truemang lại sai trong khi 2đánh giá là đúng; None==Falselà sai nhưng not Nonelà đúng!
Rolf Bartstra

9
-1 Câu trả lời này sai lệch và hoàn toàn không chính xác, vì những gì @Rolf Bartstra nói là đúng. Mặc dù trong trường hợp này, những gì bạn nói có thể được áp dụng.
HelloGoodbye

3
-1. Vì bất kỳ giá trị khác không hoặc không trống hoặc không có độ dài cho somethinglợi nhuận Truetrên bool(something). Trong trường hợp đó, nếu bạn CHỈ muốn kiểm tra xem somethingcó giá trị Truetức là không bool. Sau đó, bạn phải làm if something == TrueIMO.
Samarth Shah

2

Tôi muốn nhấn mạnh rằng, ngay cả khi có những tình huống mà if expr :không phải là đủ vì ai muốn chắc chắn exprTruekhông chỉ khác nhau từ 0/ None/ bất cứ điều gì, islà được ưa thích từ == với cùng lý do S. Lott mentionned để tránh== None .

Nó thực sự hiệu quả hơn một chút và, anh đào trên bánh, dễ đọc hơn cho con người.

In [1]: %timeit (1 == 1) == True
38.1 ns ± 0.116 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)

In [2]: %timeit (1 == 1) is True
33.7 ns ± 0.141 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)

1
Bạn không thể chạy điểm chuẩn một lần và nói rằng cái này hiệu quả hơn cái kia (mặc dù nó có thể). Chạy nó nhiều lần (10.000) để xem cách nó hoạt động trung bình. \
user1767754

1

Tôi tin rằng ném một ngoại lệ là một ý tưởng tốt hơn cho tình huống của bạn. Một thay thế sẽ là phương pháp mô phỏng để trả về một tuple. Mục đầu tiên sẽ là trạng thái và kết quả thứ hai là:

result = simulate(open("myfile"))
if not result[0]:
  print "error parsing stream"
else:
  ret= result[1]

1
trả lại tuple thường rất tốt với việc giải nén một tuple;)
SilentGhost

2
mã của bạn, tuy nhiên, không có ý nghĩa nhiều, nếu Falseđược trả lại, nó sẽ in 'error parsing stream'.
SilentGhost

Phương thức mô phỏng sẽ trả về (Sai, "mọi thứ") hoặc (Đúng, ret) trong đó ret là Sai hoặc True.
kgiannakakis

2
tốt, bạn đang xác định lại các giá trị đầu ra cho phù hợp với logic của mình, điều đó không rõ ràng với lời giải thích
SilentGhost
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.