2014-05-22 13 views
5

Tôi đã làm việc trên một dự án Python đã phát triển một phần lớn và có nhiều lớp chức năng. Do một số quyết định đầu óc đẫm máu, tôi thấy rằng tôi phải sửa chữa nhiều lỗi vì các chức năng cấp thấp hơn đang trả về loại tôi không mong đợi ở các chức năng cấp cao hơn (thường là Không).Cách pythonic để bong bóng các điều kiện lỗi

Trước khi tôi đi qua và làm sạch điều này, tôi đã tự hỏi những gì là cách pythonic nhất của chỉ ra điều kiện lỗi và xử lý chúng trong các chức năng cao hơn?

Những gì tôi đã làm cho hầu hết các phần là nếu một hàm không thể hoàn thành và trả lại kết quả mong đợi của nó, tôi sẽ trả về Không. Điều này được một chút tổng, khi bạn kết thúc phải luôn luôn kiểm tra Không có trong tất cả các chức năng gọi nó.

def lowLevel(): 
    ## some error occurred 
    return None 

    ## processing was good, return normal result string 
    return resultString 

def highLevel(): 
    resultFromLow = lowLevel() 
    if not resultFromLow: 
     return None 

    ## some processing error occurred 
    return None 

    ## processing was good, return normal result string 
    return resultString 

Tôi đoán một giải pháp khác có thể là ném ngoại lệ. Với điều đó bạn vẫn nhận được rất nhiều mã trong các hàm gọi để xử lý ngoại lệ.

Không có gì có vẻ siêu thanh lịch. Người khác sử dụng cái gì? Trong obj-c một mẫu chung là trả về tham số lỗi theo tham chiếu, và sau đó người gọi sẽ kiểm tra điều đó.

Trả lời

5

Nó thực sự phụ thuộc vào những gì bạn muốn làm về thực tế quá trình xử lý này không thể hoàn thành. Nếu đây thực sự là ngoại lệ đối với luồng điều khiển thông thường, và bạn cần dọn dẹp, bảo lãnh, gửi email cho mọi người, vv thì ngoại lệ là những gì bạn muốn ném. Trong trường hợp này, mã xử lý chỉ là công việc cần thiết, và về cơ bản là không thể tránh khỏi, mặc dù bạn có thể khôi phục lại ngăn xếp và xử lý các lỗi ở một nơi để giữ cho nó gọn gàng hơn.

Nếu các lỗi này có thể được dung thứ, thì một giải pháp thanh lịch là sử dụng mẫu Null Object. Thay vì trả về None, bạn trả về một đối tượng bắt chước giao diện của đối tượng thực thường được trả về, nhưng không làm gì cả. Điều này cho phép tất cả các mã hạ lưu của sự thất bại để tiếp tục hoạt động, không biết thực tế đã có một thất bại. Nhược điểm chính của mẫu này là nó có thể làm cho nó khó có thể phát hiện ra các lỗi thực sự, vì mã của bạn sẽ không sụp đổ, nhưng có thể không tạo ra bất cứ điều gì hữu ích khi kết thúc hoạt động của nó.

Ví dụ phổ biến về mẫu đối tượng Null trong Python đang trả về danh sách trống hoặc lệnh dict khi bạn đang ở cấp độ thấp hơn. Bất kỳ hàm tiếp theo nào sử dụng giá trị trả về này và lặp qua các phần tử sẽ chỉ rơi vào âm thầm mà không cần kiểm tra lỗi. Tất nhiên, nếu bạn yêu cầu danh sách có ít nhất một phần tử vì một số lý do, thì điều này sẽ không hoạt động và bạn sẽ quay trở lại để xử lý một tình huống ngoại lệ một lần nữa.

3

Điều này không nhất thiết phải là Pytonic như vậy nhưng kinh nghiệm đã dạy tôi để cho phép ngoại lệ "nằm ở nơi chúng nằm".

Tức là; Không cần thiết ẩn chúng hoặc tái nâng cao một ngoại lệ khác.

Đôi khi thực hành tốt để cho phép callee thất bại thay vì cố gắng nắm bắt và ẩn tất cả các loại điều kiện lỗi.

Rõ ràng chủ đề này là và có thể là một chút chủ quan; nhưng nếu bạn không ẩn hoặc nâng cao một ngoại lệ khác, thì việc gỡ lỗi mã của bạn dễ dàng hơn nhiều và dễ dàng hơn nhiều đối với các chức năng hoặc api của bạn để hiểu điều gì đã xảy ra.

Lưu ý: Câu trả lời này chưa hoàn thành - Xem nhận xét.Một số hoặc tất cả các câu trả lời được trình bày trong Q & A này có lẽ nên được kết hợp một cách tốt đẹp để giải mã các vấn đề và giải pháp khác nhau một cách rõ ràng và súc tích.

+1

Điều này bỏ lỡ mục đích chính của * re-raise * exceptions - để trình bày một API ngoại lệ hợp nhất cho người gọi. Ví dụ: nếu tôi triển khai dịch vụ web gửi trong mã của tôi bằng HTTP POST, thao tác gửi đó có thể tăng 'urllib2.HTTPError' (lỗi xử lý phía máy chủ),' urllib2.URLError' (URL sai, điểm cuối), 'ValueError '(URL không thể phân tích cú pháp hoặc thiếu),' httplibInvalidURL' (URL có thể phân tích cú pháp, nhưng không hợp lệ) và trong một số ít trường hợp, các lỗi khác. Nếu tôi không giải quyết những điều này, thì người gọi của tôi phải làm vậy. Xấu xí! Thay vào đó, tôi bắt tất cả chúng, nâng cao một ConnectionError và thêm một chuỗi ngữ cảnh khi cần thiết. –

+1

Theo như cho phép họ chỉ thất bại đi - mà chỉ hoạt động nếu bạn có thể chịu đựng các lỗi thời gian chạy kết thúc quá trình của bạn. Điều này có thể hữu ích trong thử nghiệm, nhưng đối với hầu hết các phần mềm sản xuất, đó không phải là những gì bạn muốn. –

+0

Đây là những điểm rất tốt và khá hợp lệ. Rõ ràng là một câu trả lời chấp nhận được phù hợp cần một ai đó để chi tiêu hơn 2 phút trả lời :) Tôi cảm thấy như thế này đáng lẽ phải được trả lời và thậm chí hỏi trước đó:/ –

3

Về mặt sáng, bạn đã phát hiện chính xác vấn đề với việc sử dụng giá trị trả lại để biểu thị điều kiện lỗi.

Exception s là cách giải quyết vấn đề. Câu hỏi mà bạn phải trả lời (và tôi nghi ngờ bạn đã làm) là: Có một mặc định hữu ích có thể được trả về bởi các hàm low_level không? Nếu có, hãy lấy nó và chạy với nó; nếu không, hãy tăng ngoại lệ (`ValueError ',' TypeError 'hoặc thậm chí là lỗi tùy chỉnh).

Sau đó, tăng thêm ngăn xếp cuộc gọi, nơi bạn biết cách xử lý sự cố, bắt ngoại lệ và xử lý vấn đề. Bạn không cần phải nắm bắt ngoại lệ ngay lập tức - nếu high_level gọi mid-level gọi low_level, bạn có thể không có bất kỳ try/except nào trong số mid_level và để high_level giải quyết. Có thể tất cả những gì bạn có thể làm là có một số try/except ở đầu chương trình của bạn để nắm bắt và ghi lại tất cả các lỗi chưa được khai thác và không có lỗi, và điều đó có thể không sao.

Các vấn đề liên quan