Đây có phải là một cách thực hành tốt để sử dụng thử ngoại trừ trong Python không?


437

Thỉnh thoảng trong Python, tôi thấy khối:

try:
   try_this(whatever)
except SomeException as exception:
   #Handle exception
else:
   return something

Lý do cho sự cố gắng ngoại trừ tồn tại là gì?

Tôi không thích kiểu lập trình đó, vì nó đang sử dụng các ngoại lệ để thực hiện kiểm soát luồng. Tuy nhiên, nếu nó được bao gồm trong ngôn ngữ, phải có một lý do chính đáng cho nó, phải không?

Theo hiểu biết của tôi, ngoại lệ không phải là lỗi và chúng chỉ nên được sử dụng cho các điều kiện ngoại lệ (ví dụ: tôi cố gắng ghi tệp vào đĩa và không còn chỗ trống, hoặc có thể tôi không có quyền), và không cho phép lưu lượng điều khiển.

Thông thường tôi xử lý các trường hợp ngoại lệ như:

something = some_default_value
try:
    something = try_this(whatever)
except SomeException as exception:
    #Handle exception
finally:
    return something

Hoặc nếu tôi thực sự không muốn trả lại bất cứ điều gì nếu một ngoại lệ xảy ra, thì:

try:
    something = try_this(whatever)
    return something
except SomeException as exception:
    #Handle exception

Câu trả lời:


665

"Tôi không biết liệu nó có phải là không biết gì không, nhưng tôi không thích kiểu lập trình đó, vì nó đang sử dụng các ngoại lệ để thực hiện kiểm soát dòng chảy."

Trong thế giới Python, sử dụng ngoại lệ cho điều khiển luồng là phổ biến và bình thường.

Ngay cả các nhà phát triển lõi Python cũng sử dụng ngoại lệ cho điều khiển luồng và kiểu đó được đưa vào ngôn ngữ (nghĩa là giao thức iterator sử dụng StopIteration để kết thúc vòng lặp tín hiệu).

Ngoài ra, kiểu thử ngoại trừ được sử dụng để ngăn chặn các điều kiện chủng tộc vốn có trong một số cấu trúc "nhìn trước khi bạn nhảy" . Ví dụ: kiểm tra os.path.exists dẫn đến thông tin có thể bị lỗi thời trước thời điểm bạn sử dụng. Tương tự, Queue.full trả về thông tin có thể cũ. Kiểu thử ngoại trừ sẽ tạo ra mã đáng tin cậy hơn trong những trường hợp này.

"Theo hiểu biết của tôi rằng các ngoại lệ không phải là lỗi, chúng chỉ nên được sử dụng cho các điều kiện đặc biệt"

Trong một số ngôn ngữ khác, quy tắc đó phản ánh các chuẩn mực văn hóa của họ như được phản ánh trong thư viện của họ. "Quy tắc" cũng dựa một phần vào các cân nhắc về hiệu suất cho các ngôn ngữ đó.

Chuẩn mực văn hóa Python có phần khác biệt. Trong nhiều trường hợp, bạn phải sử dụng ngoại lệ cho luồng điều khiển. Ngoài ra, việc sử dụng các ngoại lệ trong Python không làm chậm mã xung quanh và gọi mã như trong một số ngôn ngữ được biên dịch (ví dụ CPython đã triển khai mã để kiểm tra ngoại lệ ở mọi bước, bất kể bạn có thực sự sử dụng ngoại lệ hay không).

Nói cách khác, bạn hiểu rằng "ngoại lệ là dành cho ngoại lệ" là một quy tắc có ý nghĩa trong một số ngôn ngữ khác, nhưng không phải với Python.

"Tuy nhiên, nếu nó được bao gồm trong chính ngôn ngữ, phải có một lý do chính đáng cho nó, phải không?"

Bên cạnh việc giúp tránh các điều kiện chủng tộc, các ngoại lệ cũng rất hữu ích để kéo các vòng xử lý lỗi bên ngoài. Đây là một tối ưu hóa cần thiết trong các ngôn ngữ được giải thích mà không có xu hướng chuyển động mã bất biến vòng lặp tự động .

Ngoài ra, các trường hợp ngoại lệ có thể đơn giản hóa mã khá nhiều trong các tình huống phổ biến trong đó khả năng xử lý sự cố bị loại bỏ khỏi vấn đề phát sinh. Ví dụ, thông thường có mã gọi mã giao diện người dùng cấp cao nhất cho logic nghiệp vụ, từ đó gọi các thói quen cấp thấp. Các tình huống phát sinh trong các thói quen cấp thấp (như bản ghi trùng lặp cho các khóa duy nhất trong truy cập cơ sở dữ liệu) chỉ có thể được xử lý theo mã cấp cao nhất (chẳng hạn như yêu cầu người dùng cung cấp khóa mới không xung đột với các khóa hiện có). Việc sử dụng các ngoại lệ cho loại luồng điều khiển này cho phép các thói quen ở mức trung bình hoàn toàn bỏ qua vấn đề và được tách rời khỏi khía cạnh đó của điều khiển luồng.

Có một bài viết blog tốt đẹp về tính tất yếu của ngoại lệ ở đây .

Ngoài ra, hãy xem câu trả lời Stack Overflow này: Các ngoại lệ có thực sự cho các lỗi đặc biệt không?

"Lý do cho sự cố gắng - ngoại trừ - khác tồn tại là gì?"

Các mệnh đề khác là thú vị. Nó chạy khi không có ngoại lệ nhưng trước mệnh đề cuối cùng. Đó là mục đích chính của nó.

Nếu không có mệnh đề khác, tùy chọn duy nhất để chạy mã bổ sung trước khi hoàn thành sẽ là cách thực hành vụng về khi thêm mã vào mệnh đề thử. Điều đó thật vụng về vì nó có nguy cơ làm tăng các ngoại lệ trong mã không được bảo vệ bởi khối thử.

Trường hợp sử dụng chạy mã không được bảo vệ bổ sung trước khi hoàn thành không phát sinh rất thường xuyên. Vì vậy, đừng mong đợi để xem nhiều ví dụ trong mã được xuất bản. Nó hơi hiếm.

Một trường hợp sử dụng khác cho mệnh đề other là thực hiện các hành động phải xảy ra khi không có ngoại lệ xảy ra và điều đó không xảy ra khi các ngoại lệ được xử lý. Ví dụ:

recip = float('Inf')
try:
    recip = 1 / f(x)
except ZeroDivisionError:
    logging.info('Infinite result')
else:
    logging.info('Finite result')

Một ví dụ khác xảy ra ở những người chạy không đáng tin cậy nhất:

try:
    tests_run += 1
    run_testcase(case)
except Exception:
    tests_failed += 1
    logging.exception('Failing test case: %r', case)
    print('F', end='')
else:
    logging.info('Successful test case: %r', case)
    print('.', end='')

Cuối cùng, việc sử dụng phổ biến nhất của một mệnh đề khác trong khối thử là để làm đẹp một chút (căn chỉnh các kết quả đặc biệt và kết quả không đặc biệt ở cùng mức độ thụt đầu dòng). Việc sử dụng này luôn luôn là tùy chọn và không thực sự cần thiết.


28
"Điều đó thật vụng về vì nó có nguy cơ làm tăng các ngoại lệ trong mã không được bảo vệ bởi khối thử." Đây là cách học quan trọng nhất ở đây
Felix Dombek

2
Cảm ơn câu trả lời. Đối với những độc giả đang tìm kiếm các ví dụ về cách sử dụng thử ngoại trừ, hãy xem phương thức copyfile của shutil github.com/python/cpython/blob/master/Lib/shutil.py#L244
suripoori

2
Vấn đề là mệnh đề khác chỉ được thực hiện khi mệnh đề try thành công.
Jonathan

172

Lý do cho sự cố gắng ngoại trừ tồn tại là gì?

Một trykhối cho phép bạn xử lý một lỗi dự kiến. Các exceptkhối chỉ nên bắt ngoại lệ bạn đang chuẩn bị để xử lý. Nếu bạn xử lý một lỗi không mong muốn, mã của bạn có thể làm sai và ẩn lỗi.

Một elsemệnh đề sẽ thực thi nếu không có lỗi và bằng cách không thực thi mã đó trong trykhối, bạn tránh gặp lỗi không mong muốn. Một lần nữa, bắt một lỗi không mong muốn có thể ẩn lỗi.

Thí dụ

Ví dụ:

try:
    try_this(whatever)
except SomeException as the_exception:
    handle(the_exception)
else:
    return something

Bộ "thử, ngoại trừ" có hai mệnh đề tùy chọn elsefinally. Vì vậy, nó thực sự try-except-else-finally.

elsesẽ chỉ đánh giá nếu không có ngoại lệ từ trykhối. Nó cho phép chúng tôi đơn giản hóa mã phức tạp hơn dưới đây:

no_error = None
try:
    try_this(whatever)
    no_error = True
except SomeException as the_exception:
    handle(the_exception)
if no_error:
    return something

Vì vậy, nếu chúng ta so sánh với một elsegiải pháp thay thế (có thể tạo ra lỗi), chúng ta sẽ thấy rằng nó làm giảm các dòng mã và chúng ta có thể có một cơ sở mã dễ đọc hơn, dễ bảo trì hơn và ít lỗi hơn.

finally

finally sẽ thực thi bất kể điều gì, ngay cả khi một dòng khác đang được đánh giá bằng câu lệnh return.

Bị hỏng với mã giả

Nó có thể giúp phá vỡ điều này, ở dạng nhỏ nhất có thể thể hiện tất cả các tính năng, với các bình luận. Giả sử điều này đúng về mặt cú pháp (nhưng không thể chạy được trừ khi tên được xác định) mã giả nằm trong một hàm.

Ví dụ:

try:
    try_this(whatever)
except SomeException as the_exception:
    handle_SomeException(the_exception)
    # Handle a instance of SomeException or a subclass of it.
except Exception as the_exception:
    generic_handle(the_exception)
    # Handle any other exception that inherits from Exception
    # - doesn't include GeneratorExit, KeyboardInterrupt, SystemExit
    # Avoid bare `except:`
else: # there was no exception whatsoever
    return something()
    # if no exception, the "something()" gets evaluated,
    # but the return will not be executed due to the return in the
    # finally block below.
finally:
    # this block will execute no matter what, even if no exception,
    # after "something" is eval'd but before that value is returned
    # but even if there is an exception.
    # a return here will hijack the return functionality. e.g.:
    return True # hijacks the return in the else clause above

Đúng là chúng ta có thể bao gồm mã trong elsekhối trong trykhối thay vào đó, nơi nó sẽ chạy nếu không có ngoại lệ, nhưng điều gì xảy ra nếu chính mã đó phát sinh ngoại lệ của loại chúng ta đang bắt? Để nó trong trykhối sẽ che giấu lỗi đó.

Chúng tôi muốn giảm thiểu các dòng mã trong trykhối để tránh bắt ngoại lệ mà chúng tôi không mong đợi, theo nguyên tắc là nếu mã của chúng tôi thất bại, chúng tôi muốn nó thất bại lớn. Đây là một thực hành tốt nhất .

Theo hiểu biết của tôi, ngoại lệ không phải là lỗi

Trong Python, hầu hết các ngoại lệ là lỗi.

Chúng ta có thể xem hệ thống phân cấp ngoại lệ bằng cách sử dụng pydoc. Ví dụ: trong Python 2:

$ python -m pydoc exceptions

hoặc Python 3:

$ python -m pydoc builtins

Sẽ cho chúng ta thứ bậc. Chúng ta có thể thấy rằng hầu hết các loại Exceptionlà lỗi, mặc dù Python sử dụng một số trong số chúng cho những thứ như forvòng lặp kết thúc ( StopIteration). Đây là hệ thống phân cấp của Python 3:

BaseException
    Exception
        ArithmeticError
            FloatingPointError
            OverflowError
            ZeroDivisionError
        AssertionError
        AttributeError
        BufferError
        EOFError
        ImportError
            ModuleNotFoundError
        LookupError
            IndexError
            KeyError
        MemoryError
        NameError
            UnboundLocalError
        OSError
            BlockingIOError
            ChildProcessError
            ConnectionError
                BrokenPipeError
                ConnectionAbortedError
                ConnectionRefusedError
                ConnectionResetError
            FileExistsError
            FileNotFoundError
            InterruptedError
            IsADirectoryError
            NotADirectoryError
            PermissionError
            ProcessLookupError
            TimeoutError
        ReferenceError
        RuntimeError
            NotImplementedError
            RecursionError
        StopAsyncIteration
        StopIteration
        SyntaxError
            IndentationError
                TabError
        SystemError
        TypeError
        ValueError
            UnicodeError
                UnicodeDecodeError
                UnicodeEncodeError
                UnicodeTranslateError
        Warning
            BytesWarning
            DeprecationWarning
            FutureWarning
            ImportWarning
            PendingDeprecationWarning
            ResourceWarning
            RuntimeWarning
            SyntaxWarning
            UnicodeWarning
            UserWarning
    GeneratorExit
    KeyboardInterrupt
    SystemExit

Một bình luận hỏi:

Giả sử bạn có một phương thức ping API bên ngoài và bạn muốn xử lý ngoại lệ tại một lớp bên ngoài trình bao bọc API, bạn có đơn giản trả lại e từ phương thức theo mệnh đề ngoại trừ trong đó e là đối tượng ngoại lệ không?

Không, bạn không trả lại ngoại lệ, chỉ cần chỉnh lại nó bằng một khoảng trống raiseđể bảo toàn stacktrace.

try:
    try_this(whatever)
except SomeException as the_exception:
    handle(the_exception)
    raise

Hoặc, trong Python 3, bạn có thể đưa ra một ngoại lệ mới và duy trì backtrace với chuỗi ngoại lệ:

try:
    try_this(whatever)
except SomeException as the_exception:
    handle(the_exception)
    raise DifferentException from the_exception

Tôi giải thích trong câu trả lời của tôi ở đây .


nâng cao tinh thần! bạn thường làm gì bên trong phần tay cầm? giả sử bạn có một phương thức ping API bên ngoài và bạn muốn xử lý ngoại lệ tại một lớp bên ngoài trình bao bọc API, bạn có đơn giản trả lại e từ phương thức theo mệnh đề ngoại trừ trong đó e là đối tượng ngoại lệ không?
PirateApp

1
@PirateApp cảm ơn bạn! không, đừng trả lại, có lẽ bạn nên quay lại với một chuỗi trần raisehoặc làm ngoại lệ - nhưng đó là chủ đề nhiều hơn và được đề cập ở đây: stackoverflow.com/q/2052390/541136 - Có lẽ tôi sẽ xóa những nhận xét này sau khi tôi thấy bạn đã thấy chúng
Aaron Hall

cảm ơn bạn rất nhiều vì những chi tiết đi qua bài viết ngay bây giờ
PirateApp

36

Python không đăng ký ý tưởng rằng các ngoại lệ chỉ nên được sử dụng cho các trường hợp ngoại lệ, trên thực tế, thành ngữ này là 'yêu cầu sự tha thứ, không phải sự cho phép' . Điều này có nghĩa là việc sử dụng các ngoại lệ như một phần thông thường trong kiểm soát luồng của bạn là hoàn toàn có thể chấp nhận được và trên thực tế, được khuyến khích.

Điều này nói chung là một điều tốt, vì làm việc theo cách này giúp tránh một số vấn đề (như một ví dụ rõ ràng, điều kiện chủng tộc thường được tránh) và nó có xu hướng làm cho mã dễ đọc hơn một chút.

Hãy tưởng tượng bạn có một tình huống trong đó bạn lấy một số đầu vào của người dùng cần được xử lý, nhưng có một mặc định đã được xử lý. Các try: ... except: ... else: ...cấu trúc làm cho mã rất có thể đọc được:

try:
   raw_value = int(input())
except ValueError:
   value = some_processed_value
else: # no error occured
   value = process_value(raw_value)

So sánh với cách nó có thể hoạt động trong các ngôn ngữ khác:

raw_value = input()
if valid_number(raw_value):
    value = process_value(int(raw_value))
else:
    value = some_processed_value

Lưu ý những ưu điểm. Không cần phải kiểm tra giá trị là hợp lệ và phân tích nó một cách riêng biệt, chúng được thực hiện một lần. Mã cũng tuân theo một tiến trình hợp lý hơn, đường dẫn mã chính là đầu tiên, theo sau là 'nếu nó không hoạt động, hãy làm điều này'.

Ví dụ tự nhiên là một chút giả định, nhưng nó cho thấy có những trường hợp cho cấu trúc này.


15

Nó có phải là một thực hành tốt để sử dụng thử ngoại trừ-khác trong python?

Câu trả lời cho điều này là nó phụ thuộc vào bối cảnh. Nếu bạn làm điều này:

d = dict()
try:
    item = d['item']
except KeyError:
    item = 'default'

Nó chứng tỏ rằng bạn không biết Python rất rõ. Chức năng này được gói gọn trong dict.getphương thức:

item = d.get('item', 'default')

Khối try/ exceptlà một cách viết lộn xộn và trực quan hơn nhiều về cách viết có thể được thực thi hiệu quả trong một dòng duy nhất với một phương thức nguyên tử. Có những trường hợp khác mà điều này là đúng.

Tuy nhiên, điều đó không có nghĩa là chúng ta nên tránh mọi xử lý ngoại lệ. Trong một số trường hợp, nó được ưa thích để tránh các điều kiện chủng tộc. Đừng kiểm tra nếu một tập tin tồn tại, chỉ cần cố gắng mở nó và bắt IOError thích hợp. Để đơn giản và dễ đọc, hãy cố gắng gói gọn điều này hoặc đưa nó ra thành apropos.

Đọc Zen of Python , hiểu rằng có những nguyên tắc đang căng thẳng và cảnh giác với giáo điều phụ thuộc quá nhiều vào bất kỳ một tuyên bố nào trong đó.


12

Xem ví dụ sau minh họa mọi thứ về thử-ngoại trừ-khác-cuối cùng:

for i in range(3):
    try:
        y = 1 / i
    except ZeroDivisionError:
        print(f"\ti = {i}")
        print("\tError report: ZeroDivisionError")
    else:
        print(f"\ti = {i}")
        print(f"\tNo error report and y equals {y}")
    finally:
        print("Try block is run.")

Thực hiện nó và đến bởi:

    i = 0
    Error report: ZeroDivisionError
Try block is run.
    i = 1
    No error report and y equals 1.0
Try block is run.
    i = 2
    No error report and y equals 0.5
Try block is run.

3
Đây là một ví dụ đơn giản, tuyệt vời, nhanh chóng thể hiện mệnh đề thử đầy đủ mà không yêu cầu ai đó (người có thể khá vội vàng) đọc một lời giải thích trừu tượng dài. (Tất nhiên, khi họ không vội nữa, họ nên quay lại và đọc bản tóm tắt đầy đủ.)
GlobalSoftwareSociety

6

Bạn nên cẩn thận về việc sử dụng khối cuối cùng, vì nó không giống với việc sử dụng một khối khác trong thử, ngoại trừ. Khối cuối cùng sẽ được chạy bất kể kết quả của thử ngoại trừ.

In [10]: dict_ = {"a": 1}

In [11]: try:
   ....:     dict_["b"]
   ....: except KeyError:
   ....:     pass
   ....: finally:
   ....:     print "something"
   ....:     
something

Như mọi người đã lưu ý khi sử dụng khối khác khiến mã của bạn dễ đọc hơn và chỉ chạy khi không ném ngoại lệ

In [14]: try:
             dict_["b"]
         except KeyError:
             pass
         else:
             print "something"
   ....:

Tôi biết rằng cuối cùng luôn luôn được thực thi và đó là lý do tại sao nó có thể được sử dụng cho lợi thế của chúng tôi bằng cách luôn đặt giá trị mặc định, vì vậy trong trường hợp ngoại lệ, nó được trả về, nếu chúng tôi không muốn trả về giá trị đó trong trường hợp ngoại lệ, nó là đủ để loại bỏ khối cuối cùng. Btw, sử dụng pass trên một ngoại lệ bắt là điều tôi sẽ không bao giờ làm được :)
Juan Antonio Gomez Moriano

@Juan Antonio Gomez Moriano, khối mã hóa của tôi chỉ là mục đích. Tôi có lẽ cũng sẽ không bao giờ sử dụng pass
Greg

4

Bất cứ khi nào bạn thấy điều này:

try:
    y = 1 / x
except ZeroDivisionError:
    pass
else:
    return y

Hoặc thậm chí này:

try:
    return 1 / x
except ZeroDivisionError:
    return None

Thay vào đó hãy xem xét điều này:

import contextlib
with contextlib.suppress(ZeroDivisionError):
    return 1 / x

1
Nó không trả lời câu hỏi của tôi, vì đó đơn giản là một ví dụ bạn của tôi.
Juan Antonio Gomez Moriano

Trong Python, ngoại lệ không phải là lỗi. Họ thậm chí không phải là ngoại lệ. Trong Python, việc sử dụng ngoại lệ để kiểm soát luồng là điều bình thường và tự nhiên. Điều này được chứng minh bằng việc đưa contextlib.suppress () vào thư viện chuẩn. Xem câu trả lời của Raymond Hettinger tại đây: stackoverflow.com/a/16138864/1197429 (Raymond là người đóng góp Python cốt lõi và là người có thẩm quyền đối với tất cả mọi thứ Pythonic!)
Rajiv Bakulesh Shah 14/2/2017

4

Chỉ vì không ai khác đăng ý kiến ​​này, tôi sẽ nói

tránh elsecác mệnh đề try/excepts vì chúng không quen thuộc với hầu hết mọi người

Không giống như các từ khóa try, exceptfinally, ý nghĩa của elsemệnh đề không phải là hiển nhiên; nó ít đọc hơn Vì nó không được sử dụng thường xuyên, nên sẽ khiến những người đọc mã của bạn muốn kiểm tra kỹ các tài liệu để chắc chắn rằng họ hiểu những gì đang diễn ra.

(Tôi đang viết câu trả lời này một cách chính xác bởi vì tôi đã tìm thấy một try/except/elsetrong cơ sở mã của mình và nó đã gây ra một khoảnh khắc wtf và buộc tôi phải làm một số việc khác).

Vì vậy, bất cứ nơi nào tôi thấy mã như ví dụ OP:

try:
    try_this(whatever)
except SomeException as the_exception:
    handle(the_exception)
else:
    # do some more processing in non-exception case
    return something

Tôi muốn tái cấu trúc để

try:
    try_this(whatever)
except SomeException as the_exception:
    handle(the_exception)
    return  # <1>
# do some more processing in non-exception case  <2>
return something
  • <1> lợi nhuận rõ ràng, cho thấy rõ ràng, trong trường hợp ngoại lệ, chúng tôi đã hoàn thành công việc

  • <2> là một hiệu ứng phụ nhỏ, mã được sử dụng trong elsekhối được suy ra theo một cấp.


1
Đối số của đối số ác quỷ: càng nhiều người sử dụng nó, nó sẽ càng được chấp nhận nhiều hơn. Chỉ là thực phẩm cho suy nghĩ, mặc dù tôi đồng ý rằng khả năng đọc là nhập khẩu. Điều đó nói rằng, một khi ai đó hiểu thử - khác, tôi sẽ lập luận rằng nó dễ đọc hơn nhiều so với giải pháp thay thế trong nhiều trường hợp.
bob

2

Đây là đoạn mã đơn giản của tôi về cách hiểu khối thử-ngoại trừ khác cuối cùng trong Python:

def div(a, b):
    try:
        a/b
    except ZeroDivisionError:
        print("Zero Division Error detected")
    else:
        print("No Zero Division Error")
    finally:
        print("Finally the division of %d/%d is done" % (a, b))

Hãy thử div 1/1:

div(1, 1)
No Zero Division Error
Finally the division of 1/1 is done

Hãy thử div 1/0

div(1, 0)
Zero Division Error detected
Finally the division of 1/0 is done

1
Tôi nghĩ rằng điều này không thể minh họa tại sao bạn không thể đặt mã khác vào trong thử
Mojimi

-4

OP, BẠN ĐANG ĐÚNG. Cái khác sau khi thử / ngoại trừ trong Python là xấu . nó dẫn đến một đối tượng kiểm soát dòng chảy khác, nơi không cần thiết:

try:
    x = blah()
except:
    print "failed at blah()"
else:
    print "just succeeded with blah"

Một tương đương hoàn toàn rõ ràng là:

try:
    x = blah()
    print "just succeeded with blah"
except:
    print "failed at blah()"

Điều này rõ ràng hơn nhiều so với một điều khoản khác. Cái khác sau khi thử / ngoại trừ không được viết thường xuyên, vì vậy phải mất một chút thời gian để tìm hiểu ý nghĩa của nó.

Chỉ vì bạn CÓ THỂ làm một việc, không có nghĩa là bạn NÊN làm một việc.

Rất nhiều tính năng đã được thêm vào ngôn ngữ vì ai đó nghĩ rằng nó có thể có ích. Rắc rối là, càng nhiều tính năng, những điều ít rõ ràng và rõ ràng là do mọi người thường không sử dụng những chiếc chuông và còi đó.

Chỉ cần 5 xu của tôi ở đây. Tôi phải đi theo phía sau và dọn sạch rất nhiều mã được viết bởi những nhà phát triển đại học năm thứ nhất, những người nghĩ rằng họ thông minh và muốn viết mã theo một cách chặt chẽ, hiệu quả nhất khi điều đó làm cho nó trở nên lộn xộn để thử và đọc / sửa đổi sau này. Tôi bỏ phiếu cho khả năng đọc mỗi ngày và hai lần vào Chủ nhật.


15
Bạn đúng. Điều đó hoàn toàn rõ ràng và tương đương ... trừ khi đó là printtuyên bố của bạn thất bại. Điều gì xảy ra nếu x = blah()trả về a str, nhưng câu lệnh in của bạn là print 'just succeeded with blah. x == %d' % x? Bây giờ bạn đã có một TypeErrorsinh vật mà bạn chưa sẵn sàng để xử lý một; bạn đang kiểm tra x = blah()để tìm nguồn gốc của ngoại lệ, và nó thậm chí không có ở đó. Tôi đã thực hiện điều này (hoặc tương đương) hơn một lần khi điều đó elsesẽ khiến tôi không phạm phải sai lầm này. Bây giờ tôi biết rõ hơn. :-D
Doug R.

2
... Và vâng, bạn đúng. Các elsekhoản không phải là một tuyên bố khá, và cho đến khi bạn đã quen với nó, nó không trực quan. Nhưng sau đó, finallylần đầu tiên tôi không bắt đầu sử dụng nó ...
Doug R.

2
Để lặp lại Doug R., nó không tương đương vì các ngoại lệ trong các câu trong elsemệnh đề không bị bắt bởi except.
alastair

nếu ... ngoại trừ ... khác dễ đọc hơn, nếu không bạn phải đọc "oh, sau khi thử khối và không có ngoại lệ, hãy chuyển đến câu lệnh bên ngoài khối thử", vì vậy sử dụng cách khác: có xu hướng kết nối cú pháp một chút về mặt ngữ nghĩa imo tốt hơn. Ngoài ra, cách tốt nhất là để các tuyên bố chưa được khai thác của bạn bên ngoài khối thử ban đầu.
cowbert

1
@DougR. "Bạn đang kiểm tra x = blah()để tìm nguồn gốc của ngoại lệ", tracebackTại sao bạn lại kiểm tra nguồn ngoại lệ từ một vị trí sai?
nehem
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.