Kiểm tra đầu tiên và xử lý ngoại lệ?


88

Tôi đang làm việc thông qua cuốn sách "Head First Python" (đây là ngôn ngữ của tôi để học trong năm nay) và tôi đã đến một phần mà họ tranh luận về hai kỹ thuật mã:
Kiểm tra đầu tiên và xử lý ngoại lệ.

Đây là một mẫu mã Python:

# Checking First
for eachLine in open("../../data/sketch.txt"):
    if eachLine.find(":") != -1:
        (role, lineSpoken) = eachLine.split(":",1)
        print("role=%(role)s lineSpoken=%(lineSpoken)s" % locals())

# Exception handling        
for eachLine in open("../../data/sketch.txt"):
    try:
        (role, lineSpoken) = eachLine.split(":",1)
        print("role=%(role)s lineSpoken=%(lineSpoken)s" % locals())
    except:
        pass

Ví dụ đầu tiên xử lý trực tiếp một vấn đề trong .splithàm. Cái thứ hai chỉ để xử lý ngoại lệ xử lý nó (và bỏ qua vấn đề).

Họ lập luận trong cuốn sách để sử dụng xử lý ngoại lệ thay vì kiểm tra trước. Đối số là mã ngoại lệ sẽ bắt tất cả các lỗi, trong đó kiểm tra trước sẽ chỉ bắt những điều bạn nghĩ về (và bạn bỏ lỡ các trường hợp góc). Tôi đã được dạy để kiểm tra trước, vì vậy bản năng nội tâm của tôi là làm điều đó, nhưng ý tưởng của họ rất thú vị. Tôi chưa bao giờ nghĩ đến việc sử dụng xử lý ngoại lệ để giải quyết các trường hợp.

Cái nào trong hai cái thường được coi là thực hành tốt hơn?


12
Phần đó trong cuốn sách không thông minh. Nếu bạn đang ở trong một vòng lặp và bạn đang ném ngoại lệ nhiều lần. Tôi đã cố gắng phác thảo một số điểm tốt khi làm điều này.
Jason Sebring

9
Chỉ cần không rơi vào bẫy "kiểm tra tập tin tồn tại". File tồn tại = có quyền truy cập tập tin, hoặc là nó sẽ tồn tại trong 10 ms nó cần để có được lời kêu gọi mở tập tin của tôi, vv! Blogs.msdn.com/b/jaredpar/archive/2009/04/27/...
Billy ONeal

11
Các ngoại lệ được cho là khác nhau trong Python so với các ngôn ngữ khác. Chẳng hạn, cách lặp qua bộ sưu tập là gọi .next () trên đó cho đến khi nó ném ngoại lệ.
WuHoUnited

4
@ emeraldcode.com Điều đó không hoàn toàn đúng về Python. Tôi không biết chi tiết cụ thể, nhưng ngôn ngữ đã được xây dựng xung quanh mô hình đó, vì vậy việc ném ngoại lệ gần như không tốn kém như trong các ngôn ngữ khác.
Izkata

Điều đó nói rằng, trong ví dụ này, tôi sẽ sử dụng một tuyên bố bảo vệ: if -1 == eachLine.find(":"): continuesau đó, phần còn lại của vòng lặp cũng sẽ không được thụt lề.
Izkata

Câu trả lời:


68

Trong .NET, thông thường là tránh lạm dụng Ngoại lệ. Một đối số là hiệu suất: trong .NET, ném một ngoại lệ là tính toán tốn kém.

Một lý do khác để tránh việc lạm dụng chúng là việc đọc mã mà phụ thuộc quá nhiều vào chúng có thể rất khó khăn. Mục blog của Joel Spolsky thực hiện tốt công việc mô tả vấn đề.

Tại trung tâm của cuộc tranh luận là trích dẫn sau đây:

Lý do là tôi coi các trường hợp ngoại lệ không tốt hơn "goto", được coi là có hại từ những năm 1960, trong đó chúng tạo ra một bước nhảy đột ngột từ điểm này sang điểm khác. Trên thực tế, chúng còn tệ hơn đáng kể so với goto:

1. Chúng vô hình trong mã nguồn . Nhìn vào một khối mã, bao gồm các hàm có thể hoặc không thể ném ngoại lệ, không có cách nào để xem ngoại lệ nào có thể được ném và từ đâu. Điều này có nghĩa là ngay cả việc kiểm tra mã cẩn thận cũng không tiết lộ các lỗi tiềm ẩn.

2. Chúng tạo quá nhiều điểm thoát có thể cho một hàm. Để viết mã chính xác, bạn thực sự phải suy nghĩ về mọi đường dẫn mã có thể thông qua chức năng của bạn. Mỗi khi bạn gọi một hàm có thể đưa ra một ngoại lệ và không bắt gặp nó ngay lập tức, bạn sẽ tạo cơ hội cho các lỗi bất ngờ gây ra bởi các hàm bị chấm dứt đột ngột, khiến dữ liệu ở trạng thái không nhất quán hoặc các đường dẫn mã khác mà bạn không nghĩ về.

Cá nhân, tôi ném ngoại lệ khi mã của tôi không thể làm những gì nó được ký hợp đồng để làm. Tôi có xu hướng sử dụng thử / bắt khi tôi sắp xử lý một cái gì đó nằm ngoài ranh giới quy trình của mình, ví dụ như một cuộc gọi SOAP, một cuộc gọi cơ sở dữ liệu, tệp IO hoặc một cuộc gọi hệ thống. Nếu không, tôi cố gắng để mã hóa phòng thủ. Đó không phải là một quy tắc khó và nhanh, nhưng đó là một thông lệ chung.

Scott Hanselman cũng viết về các ngoại lệ trong .NET ở đây . Trong bài viết này, ông mô tả một số quy tắc về ngoại lệ. Yêu thích của tôi?

Bạn không nên ném ngoại lệ cho những điều xảy ra mọi lúc. Sau đó, họ sẽ là "pháp lệnh".


5
Đây là một điểm khác: nếu ghi nhật ký ngoại lệ được kích hoạt trên toàn ứng dụng, tốt hơn là chỉ sử dụng ngoại lệ cho các điều kiện ngoại lệ, không phải cho các quy tắc. Nếu không, nhật ký sẽ trở nên lộn xộn và các lý do gây ra lỗi thực sự sẽ bị che khuất.
rwong

2
Câu trả lời tốt đẹp. Lưu ý mặc dù các trường hợp ngoại lệ có hiệu suất cao trên hầu hết các nền tảng. Tuy nhiên, như bạn đã lưu ý với nhận xét của tôi về các câu trả lời khác, hiệu suất không phải là điều cần cân nhắc trong trường hợp quyết định quy tắc chăn cho cách mã hóa một cái gì đó.
mattnz

1
Trích dẫn từ Scott Hanselman mô tả tốt hơn thái độ .Net đối với các ngoại lệ hơn là "lạm dụng". Hiệu suất thường được đề cập, nhưng đối số thực tế là nghịch đảo tại sao bạn NÊN sử dụng các ngoại lệ - nó làm cho mã khó hiểu và xử lý hơn khi một điều kiện thông thường dẫn đến ngoại lệ. Đối với Joel, điểm 1 thực sự là một điểm tích cực (vô hình có nghĩa là mã cho thấy những gì nó làm, không phải những gì nó không) và điểm 2 không liên quan (bạn đã ở trong trạng thái không nhất quán hoặc không nên có ngoại lệ) . Tuy nhiên, +1 cho "không thể làm những gì nó được yêu cầu".
jmoreno

5
Mặc dù câu trả lời này là tốt cho .Net, nhưng nó không phải là pythonic , vì vậy đây là một câu hỏi trăn, tôi không biết tại sao câu trả lời của Ivc đã không được bình chọn nhiều hơn.
Đánh dấu gian hàng

2
@IanGoldby: không. Xử lý ngoại lệ thực sự được mô tả tốt hơn là phục hồi ngoại lệ. Nếu bạn không thể khôi phục từ một ngoại lệ, thì có lẽ bạn không nên có bất kỳ mã xử lý ngoại lệ nào. Nếu phương thức A gọi phương thức B gọi C và C ném, thì rất có thể EITHER A OR B sẽ phục hồi, không phải cả hai. Nên tránh quyết định "nếu tôi không thể làm X Tôi sẽ làm Y" nếu Y yêu cầu người khác hoàn thành nhiệm vụ. Nếu bạn không thể hoàn thành nhiệm vụ, tất cả những gì còn lại là dọn dẹp và đăng nhập. Dọn dẹp trong .net nên được tự động, đăng nhập nên được tập trung.
jmoreno

78

Trong Python nói riêng, nó thường được coi là thực hành tốt hơn để bắt ngoại lệ. Nó có xu hướng được gọi là Dễ dàng hơn để yêu cầu sự tha thứ so với sự cho phép (EAFP), so với Look Before You Leap (LBYL). Có những trường hợp LBYL sẽ cung cấp cho bạn các lỗi tinh tế trong một số trường hợp.

Tuy nhiên, hãy cẩn thận với các tuyên bố trầnexcept: cũng như vượt quá các báo cáo, vì cả hai cũng có thể che giấu các lỗi - một cái gì đó như thế này sẽ tốt hơn:

for eachLine in open("../../data/sketch.txt"):
    try:
        role, lineSpoken = eachLine.split(":",1)
    except ValueError:
        pass
    else:
        print("role=%(role)s lineSpoken=%(lineSpoken)s" % locals())

8
Là một lập trình viên .NET, tôi chê cái này. Nhưng sau đó, một lần nữa, mọi người làm mọi thứ kỳ lạ. :)
Phil

Điều này đặc biệt gây khó chịu (chơi chữ không có ý định) khi các API không nhất quán về trường hợp ngoại lệ nào được đưa ra trong trường hợp nào hoặc khi nhiều loại lỗi khác nhau được ném theo cùng một loại ngoại lệ.
Jack

Vì vậy, cuối cùng bạn sử dụng cùng một cơ chế cho các lỗi không mong muốn và loại giá trị trả về dự kiến. Điều đó cũng tuyệt vời như việc sử dụng 0 làm số, một bool giả và một con trỏ không hợp lệ sẽ thoát khỏi quy trình của bạn với mã thoát 128 + SIGSEGV, vì giờ đây bạn thuận tiện đến mức nào. Giống như con cò! Hoặc giày có ngón chân ...
yeoman

2
@yeoman khi ném một ngoại lệ là một câu hỏi khác nhau, chương trình này là về việc sử dụng try/ exceptchứ không phải thiết lập một điều kiện cho "là khả năng sau đây để ném một ngoại lệ", và thực hành Python chắc chắn là thích cũ. Điều đó không làm tổn hại rằng cách tiếp cận đó (có lẽ) hiệu quả hơn ở đây, vì, trong trường hợp phân tách thành công, bạn chỉ đi bộ chuỗi một lần. Về việc có splitnên ném ngoại lệ ở đây hay không, tôi chắc chắn sẽ nói rằng - một quy tắc phổ biến là bạn nên ném khi bạn không thể làm những gì tên của bạn nói, và bạn không thể phân chia ở một dấu phân cách bị thiếu.
lvc

Tôi không thấy nó xấu hay chậm hay khủng khiếp, đặc biệt là chỉ có một ngoại lệ cụ thể được bắt gặp. Tôi thực sự thích Python. Thật buồn cười khi đôi khi nó không có mùi vị gì cả, như đã nói C sử dụng số 0, Spork và giày yêu thích mọi thời đại của Randall Munroe bằng ngón chân :) Plus, khi tôi ở Python và API nói rằng đây là Cách để làm điều đó, tôi sẽ thực hiện nó :) Kiểm tra các điều kiện trước tất nhiên không bao giờ là một ý tưởng hay vì đồng thời, coroutines hoặc một trong những thứ được thêm vào dưới đường ...
yeoman

27

Cách tiếp cận thực dụng

Bạn nên phòng thủ nhưng đến một điểm. Bạn nên viết xử lý ngoại lệ nhưng đến một điểm. Tôi sẽ sử dụng lập trình web làm ví dụ vì đây là nơi tôi sống.

  1. Giả sử tất cả đầu vào của người dùng là xấu và chỉ viết phòng thủ đến điểm xác minh kiểu dữ liệu, kiểm tra mẫu và tiêm độc hại. Lập trình phòng thủ phải là những thứ có khả năng xảy ra rất thường xuyên mà bạn không thể kiểm soát.
  2. Viết xử lý ngoại lệ cho các dịch vụ được nối mạng đôi khi có thể bị lỗi và xử lý một cách duyên dáng cho phản hồi của người dùng. Lập trình ngoại lệ nên được sử dụng cho những thứ được nối mạng đôi khi có thể bị lỗi nhưng thường rất chắc chắn VÀ bạn cần giữ cho chương trình của mình hoạt động.
  3. Đừng bận tâm viết phòng thủ trong ứng dụng của bạn sau khi dữ liệu đầu vào được xác thực. Thật lãng phí thời gian và làm phồng ứng dụng của bạn. Hãy để nó nổ tung vì một trong những thứ rất hiếm không đáng để xử lý hoặc điều đó có nghĩa là bạn cần xem xét kỹ hơn về bước 1 và 2.
  4. Không bao giờ viết xử lý ngoại lệ trong mã lõi của bạn không phụ thuộc vào thiết bị được nối mạng. Làm như vậy là lập trình xấu và tốn kém cho hiệu suất. Ví dụ, viết một lần thử trong trường hợp vượt ra khỏi giới hạn trong một vòng lặp có nghĩa là bạn đã không lập trình vòng lặp chính xác ở vị trí đầu tiên.
  5. Hãy để mọi thứ được xử lý bằng cách ghi nhật ký lỗi trung tâm bắt ngoại lệ ở một nơi sau khi làm theo các quy trình trên. Bạn không thể bắt mọi trường hợp cạnh vì điều đó có thể là vô hạn, bạn chỉ cần viết mã xử lý hoạt động dự kiến. Đó là lý do tại sao bạn sử dụng xử lý lỗi trung tâm như là phương sách cuối cùng.
  6. TDD là tốt bởi vì theo một cách nào đó là cố gắng bắt bạn mà không phình to, có nghĩa là mang lại cho bạn một số đảm bảo hoạt động bình thường.
  7. Điểm thưởng là sử dụng một công cụ bao phủ mã, ví dụ Istanbul là một công cụ tốt cho nút vì điều này cho bạn thấy nơi bạn không thử nghiệm.
  8. Thông báo trước cho tất cả những điều này là ngoại lệ thân thiện với nhà phát triển . Ví dụ, một ngôn ngữ sẽ ném nếu bạn sử dụng cú pháp sai và giải thích lý do. Vì vậy, các thư viện tiện ích của bạn mà phần lớn mã của bạn phụ thuộc vào.

Đây là từ kinh nghiệm làm việc trong các kịch bản nhóm lớn.

Tương tự

Hãy tưởng tượng nếu bạn mặc một bộ đồ không gian bên trong ISS TẤT CẢ thời gian. Thật khó để đi vệ sinh hay ăn uống. Nó sẽ siêu cồng kềnh bên trong mô-đun không gian để di chuyển xung quanh. Nó sẽ hút. Viết một loạt các lần thử trong mã của bạn là như thế. Bạn phải có một số điểm mà bạn nói, hey tôi đã bảo đảm ISS và các phi hành gia của tôi bên trong đều ổn, vì vậy việc mặc một bộ đồ vũ trụ cho mọi tình huống có thể xảy ra là không thực tế.


4
Vấn đề với Điểm 3 là nó giả định chương trình và các lập trình viên làm việc với nó, là hoàn hảo. Họ không, vì vậy đây là chương trình tốt nhất phòng thủ với những điều này trong tâm trí. Xuất hiện số lượng tại thời điểm quan trọng có thể làm cho phần mềm trở nên đáng tin cậy hơn nhiều so với tâm lý "Nếu đầu vào được kiểm tra mọi thứ hoàn hảo".
mattnz

đó là những gì thử nghiệm dành cho.
Jason Sebring

3
Kiểm tra không phải là một bắt tất cả. Tôi vẫn chưa thấy một bộ thử nghiệm có mã 100% và phạm vi bảo hiểm "môi trường".
Marjan Venema

1
@emeraldcode: Bạn có muốn có một công việc với tôi không, tôi rất thích có ai đó trong nhóm luôn luôn, ngoại trừ, kiểm tra mọi hoán vị của mọi trường hợp cạnh mà phần mềm sẽ thực hiện. Phải biết rằng abosoluite chắc chắn rằng mã của bạn đã được kiểm tra một cách hoàn hảo.
mattnz

1
Đồng ý. Có những kịch bản mà cả lập trình phòng thủ và xử lý ngoại lệ đều hoạt động tốt và xấu, và chúng ta là những lập trình viên nên học cách nhận ra chúng, và chọn kỹ thuật phù hợp nhất. Tôi thích Điểm 3 vì tôi tin rằng chúng ta cần giả định, ở một mức độ nhất định của mã, rằng một số điều kiện theo ngữ cảnh nên được thỏa mãn. Các điều kiện này được thỏa mãn bằng cách mã hóa phòng thủ ở lớp mã bên ngoài và tôi nghĩ rằng xử lý ngoại lệ là phù hợp khi các giả định này bị phá vỡ ở lớp bên trong.
yaobin

15

Đối số chính của cuốn sách là phiên bản ngoại lệ của mã tốt hơn bởi vì nó sẽ nắm bắt mọi thứ mà bạn có thể đã bỏ qua nếu bạn cố gắng viết kiểm tra lỗi của riêng bạn.

Tôi nghĩ rằng tuyên bố này chỉ đúng trong những trường hợp rất cụ thể - nơi bạn không quan tâm nếu đầu ra là chính xác.

Không có nghi ngờ rằng việc nâng cao ngoại lệ là một thực hành đúng đắn và an toàn. Bạn nên làm như vậy bất cứ khi nào bạn cảm thấy có điều gì đó trong trạng thái hiện tại của chương trình mà bạn (với tư cách là nhà phát triển) không thể hoặc không muốn giải quyết.

Ví dụ của bạn, tuy nhiên, là về việc bắt ngoại lệ. Nếu bạn bắt gặp một ngoại lệ, bạn không tự bảo vệ mình khỏi các tình huống mà bạn có thể đã bỏ qua. Bạn đang làm chính xác điều ngược lại: bạn cho rằng bạn đã bỏ qua bất kỳ kịch bản nào có thể gây ra loại ngoại lệ này, và do đó bạn tự tin rằng việc nắm bắt nó (và do đó ngăn không cho chương trình thoát ra, như bất kỳ ngoại lệ chưa được khai thác nào).

Sử dụng phương pháp ngoại lệ, nếu bạn thấy ValueErrorngoại lệ, bạn bỏ qua một dòng. Sử dụng phương pháp tiếp cận không ngoại lệ truyền thống, bạn đếm số lượng giá trị được trả về splitvà nếu nó nhỏ hơn 2, bạn bỏ qua một dòng. Bạn có nên cảm thấy an toàn hơn với cách tiếp cận ngoại lệ, vì bạn có thể đã quên một số tình huống "lỗi" khác trong kiểm tra lỗi truyền thống của mình và except ValueErrorsẽ bắt chúng cho bạn?

Điều này phụ thuộc vào bản chất của chương trình của bạn.

Nếu bạn đang viết, ví dụ, trình duyệt web hoặc trình phát video, một vấn đề với đầu vào sẽ không khiến nó bị sập với một ngoại lệ chưa được lưu. Tốt hơn hết là xuất ra thứ gì đó hợp lý từ xa (ngay cả khi, nói đúng ra là không chính xác) hơn là bỏ.

Nếu bạn đang viết một ứng dụng mà vấn đề chính xác (như phần mềm kinh doanh hoặc kỹ thuật), đây sẽ là một cách tiếp cận tồi tệ. Nếu bạn quên một số kịch bản phát sinh ValueError, điều tồi tệ nhất bạn có thể làm là âm thầm bỏ qua kịch bản chưa biết này và chỉ cần bỏ qua dòng. Đó là cách các lỗi rất tinh vi và tốn kém kết thúc trong phần mềm.

Bạn có thể nghĩ rằng cách duy nhất bạn có thể thấy ValueErrortrong mã này là nếu splitchỉ được trả về một giá trị (thay vì hai). Nhưng điều gì sẽ xảy ra nếu printcâu lệnh của bạn sau đó bắt đầu sử dụng một biểu thức tăng lên ValueErrortrong một số điều kiện? Điều này sẽ khiến bạn bỏ qua một số dòng không phải vì họ bỏ lỡ :, mà vì printthất bại trên chúng. Đây là một ví dụ về một lỗi tinh vi mà tôi đã đề cập trước đó - bạn sẽ không nhận thấy bất cứ điều gì, chỉ mất một số dòng.

Đề nghị của tôi là tránh bắt (nhưng không nêu ra!) Ngoại lệ trong mã nơi sản xuất đầu ra không chính xác còn tệ hơn thoát. Lần duy nhất tôi bắt gặp một ngoại lệ trong mã như vậy là khi tôi có một biểu thức thực sự tầm thường, vì vậy tôi có thể dễ dàng suy luận điều gì có thể gây ra từng loại ngoại lệ có thể.

Đối với tác động hiệu suất của việc sử dụng các ngoại lệ, nó là tầm thường (trong Python) trừ khi gặp phải các ngoại lệ thường xuyên.

Nếu bạn sử dụng ngoại lệ để xử lý các điều kiện xảy ra thường xuyên, trong một số trường hợp, bạn có thể phải trả một chi phí hiệu suất rất lớn. Ví dụ, giả sử bạn thực hiện từ xa một số lệnh. Bạn có thể kiểm tra xem văn bản lệnh của bạn vượt qua ít nhất là xác thực tối thiểu (ví dụ: cú pháp). Hoặc bạn có thể đợi một ngoại lệ được đưa ra (điều này chỉ xảy ra sau khi máy chủ từ xa phân tích cú pháp lệnh của bạn và tìm thấy sự cố với nó). Rõ ràng, trước đây là đơn đặt hàng cường độ nhanh hơn. Một ví dụ đơn giản khác: bạn có thể kiểm tra xem một số có nhanh hơn 0 ~ 10 lần so với cố gắng thực hiện phép chia hay không và sau đó bắt ngoại lệ ZeroDivisionError.

Những cân nhắc này chỉ quan trọng nếu bạn thường xuyên gửi các chuỗi lệnh không đúng định dạng đến các máy chủ từ xa hoặc nhận các đối số có giá trị bằng 0 mà bạn sử dụng để phân chia.

Lưu ý: Tôi giả sử bạn sẽ sử dụng except ValueErrorthay vì chỉ except; như những người khác đã chỉ ra, và như cuốn sách đã nói trong một vài trang, bạn không bao giờ nên sử dụng trần except.

Một lưu ý khác: cách tiếp cận không ngoại lệ thích hợp là đếm số lượng giá trị được trả về split, thay vì tìm kiếm :. Cái sau thì quá chậm, vì nó lặp lại công việc được thực hiện bởi splitvà có thể tăng gần gấp đôi thời gian thực hiện.


6

Theo nguyên tắc chung, nếu bạn biết một tuyên bố có thể tạo ra kết quả không hợp lệ, hãy kiểm tra điều đó và xử lý nó. Sử dụng ngoại lệ cho những điều bạn không mong đợi; những thứ "đặc biệt". Nó làm cho mã rõ ràng hơn theo nghĩa hợp đồng ("không nên là null" làm ví dụ).


2

Sử dụng những gì từng hoạt động tốt trong ..

  • ngôn ngữ lập trình bạn đã chọn về khả năng đọc và hiệu quả của mã
  • nhóm của bạn và tập hợp các quy ước mã đã thống nhất

Cả xử lý ngoại lệ và lập trình phòng thủ là những cách khác nhau để thể hiện cùng một mục đích.


0

TBH, không vấn đề gì nếu bạn sử dụng try/exceptmáy móc hoặc ifkiểm tra câu lệnh. Bạn thường thấy cả EAFP và LBYL trong hầu hết các đường cơ sở Python, với EAFP là phổ biến hơn một chút. Đôi khi EAFP nhiều hơn nữa có thể đọc / thành ngữ, nhưng trong trường hợp đặc biệt này, tôi nghĩ rằng nó là tốt một trong hai cách.

Tuy nhiên...

Tôi sẽ cẩn thận khi sử dụng tài liệu tham khảo hiện tại của bạn. Một vài vấn đề rõ ràng với mã của họ:

  1. Các mô tả tập tin bị rò rỉ. Các phiên bản hiện đại của CPython (một trình thông dịch Python cụ thể ) sẽ thực sự đóng nó, vì đó là một đối tượng ẩn danh chỉ có phạm vi trong vòng lặp (gc sẽ nuke nó sau vòng lặp). Tuy nhiên, các thông dịch viên khác không có sự đảm bảo này. Họ có thể rò rỉ mô tả hoàn toàn. Bạn hầu như luôn muốn sử dụng withthành ngữ khi đọc tệp trong Python: có rất ít ngoại lệ. Đây không phải là một trong số họ.
  2. Việc xử lý ngoại lệ của Pokemon được tán thành khi nó che giấu các lỗi (tức là excepttuyên bố trần không bắt được một ngoại lệ cụ thể)
  3. Nit: Bạn không cần parens để giải nén. Chỉ có thể làmrole, lineSpoken = eachLine.split(":",1)

Ivc có một câu trả lời tốt về điều này và EAFP, nhưng cũng đang rò rỉ mô tả.

Phiên bản LBYL không nhất thiết phải có hiệu suất như phiên bản EAFP, do đó, nói rằng việc ném ngoại lệ là "đắt về mặt hiệu suất" là sai về mặt phân loại. Nó thực sự phụ thuộc vào loại chuỗi bạn đang xử lý:

In [33]: def lbyl(lines):
    ...:     for line in lines:
    ...:         if line.find(":") != -1:
    ...:             # Nuke the parens, do tuple unpacking like an idiomatic Python dev.
    ...:             role, lineSpoken = line.split(":",1)
    ...:             # no print, since output is obnoxiously long with %timeit
    ...:

In [34]: def eafp(lines):
    ...:     for line in lines:
    ...:         try:
    ...:             # Nuke the parens, do tuple unpacking like an idiomatic Python dev.
    ...:             role, lineSpoken = eachLine.split(":",1)
    ...:             # no print, since output is obnoxiously long with %timeit
    ...:         except:
    ...:             pass
    ...:

In [35]: lines = ["abc:def", "onetwothree", "xyz:hij"]

In [36]: %timeit lbyl(lines)
100000 loops, best of 3: 1.96 µs per loop

In [37]: %timeit eafp(lines)
100000 loops, best of 3: 4.02 µs per loop

In [38]: lines = ["a"*100000 + ":" + "b", "onetwothree", "abconetwothree"*100]

In [39]: %timeit lbyl(lines)
10000 loops, best of 3: 119 µs per loop

In [40]: %timeit eafp(lines)
100000 loops, best of 3: 4.2 µs per loop

-4

Về cơ bản, xử lý ngoại lệ được cho là phù hợp hơn với các ngôn ngữ OOP.

Điểm thứ hai là hiệu suất, bởi vì bạn không phải thực thi eachLine.findcho mỗi dòng.


7
-1: Hiệu suất là một lý do cực kỳ kém cho các quy tắc chăn.
mattnz

3
Không, ngoại lệ hoàn toàn không liên quan đến OOP.
Pubby

-6

Tôi nghĩ rằng lập trình phòng thủ làm tổn thương hiệu suất. Bạn cũng chỉ nên nắm bắt các ngoại lệ bạn sẽ xử lý, hãy để thời gian chạy xử lý ngoại lệ bạn không biết cách xử lý.


7
Tuy nhiên, anotehr -1 vì lo lắng về hiệu suất trên mức độ sẵn sàng, tính duy trì bla bla bla. Hiệu suất không phải là một lý do.
mattnz

Tôi có thể biết tại sao bạn chạy xung quanh phân phối -1 mà không giải thích không? Lập trình phòng thủ có nghĩa là nhiều dòng mã hơn, có nghĩa là hiệu suất kém hơn. Bất cứ ai quan tâm để giải thích trước khi bắn hạ điểm số?
Manoj

3
@Manoj: Trừ khi bạn đo bằng trình lược tả và thấy một khối mã chậm đến mức không thể chấp nhận được, mã cho khả năng đọc và khả năng bảo trì trước khi thực hiện.
Daenyth

Những gì @Manoj nói với việc bổ sung rằng ít mã hơn có nghĩa là ít hoạt động hơn khi gỡ lỗi và bảo trì. Lượt truy cập vào thời gian của nhà phát triển cho bất cứ điều gì ít hơn mà mã hoàn hảo là cực kỳ cao. Tôi giả sử (như tôi) bạn không viết mã hoàn hảo, hãy tha thứ cho tôi nếu tôi sai.
mattnz

2
Cảm ơn về liên kết - Đọc thú vị mà tôi phải đồng ý với nó, đến một điểm ... Làm việc trên một hệ thống quan trọng trong cuộc sống, như tôi làm "Hệ thống đã in dấu vết ngăn xếp, vì vậy chúng tôi biết chính xác tại sao 300 người đó chết không cần thiết. .... "sẽ không thực sự đi xuống quá tốt trong bục nhân chứng. Tôi cho rằng đó là một trong những điều mà mọi tình huống đều có phản ứng thích hợp khác nhau.
mattnz
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.