2011-09-06 16 views
7

Tôi có một số chức năng phân tích cú pháp dữ liệu từ các tệp, thường trả về một danh sách các kết quả.Tôi muốn trả về một giá trị VÀ nêu ra một ngoại lệ, điều này có nghĩa là tôi đang làm điều gì sai?

Nếu tôi gặp phải một đường tinh ranh trong tệp, tôi muốn người lính và xử lý các dòng hợp lệ và trả lại chúng. Nhưng tôi cũng muốn báo cáo lỗi cho chức năng gọi. Lý do tôi muốn báo cáo nó là để các chức năng gọi điện thoại có thể thông báo cho người dùng rằng các tập tin cần xem xét. Tôi không muốn bắt đầu làm những thứ GUI trong chức năng phân tích cú pháp, vì điều đó dường như là một sự vi phạm lớn về việc phân tách các mối quan tâm. Chức năng phân tích cú pháp không có quyền truy cập vào bảng điều khiển Tôi vẫn đang viết thông báo lỗi.

Điều này khiến tôi muốn trả lại dữ liệu thành công, nhưng cũng tăng ngoại lệ do lỗi, điều này rõ ràng là tôi không thể làm được.

xem xét mã này:

try: 
    parseResult = parse(myFile) 
except MyErrorClass, e: 
    HandleErrorsSomehow(str(e)) 

def parse(file): #file is a list of lines from an actual file 
    err = False 
    result = [] 

    for lines in file: 
     processedLine = Process(line) 
     if not processedLine: 
      err = True 
     else 
      result.append(processedLine) 
    return result 
    if err: 
     raise MyErrorClass("Something went wrong") 

Rõ ràng là ba dòng cuối cùng làm cho không có ý nghĩa, nhưng tôi không thể tìm ra một cách tốt đẹp để làm điều này. Tôi đoán tôi có thể làm return (err, result), và gọi nó là như

parseErr, parseResult = parse(file) 
if parseErr: 
    HandleErrorsSomehow() 

Nhưng trở về mã lỗi dường như đủ un-pythonic, hãy để một mình trở về tuples của mã lỗi và các giá trị kết quả thực tế.

Thực tế là tôi cảm thấy như tôi muốn làm điều gì đó kỳ lạ trong một ứng dụng không thực sự phức tạp đến mức khủng khiếp, khiến tôi nghĩ rằng có lẽ tôi đang làm điều gì đó sai. Có một giải pháp tốt hơn cho vấn đề này? Hoặc có cách nào để tôi có thể sử dụng finally để trả lại giá trị và tăng ngoại lệ cùng một lúc không?

+0

Trong trường hợp này, tôi có lẽ sẽ trả về một tuple 'processedData, errorInformation', với' errorInformation' là một chuỗi rỗng nếu không có lỗi xảy ra. Một tùy chọn khác là sử dụng chức năng gọi lại, được gọi với một số thông tin lỗi nếu xảy ra lỗi - nếu người gọi không quan tâm, nó có thể chuyển 'Không' làm cuộc gọi lại. –

Trả lời

7

Không ai nói chỉ chỉ cách hợp lệ để xử lý "lỗi" là ném ngoại lệ. Trong thiết kế của bạn, người gọi muốn hai mẩu thông tin: (1) dữ liệu hợp lệ, (2) có xảy ra lỗi không (và có thể có điều gì đó sai về đâu, vì vậy nó có thể định dạng thông báo lỗi hữu ích). Đó là trường hợp hoàn toàn hợp lệ và trên mặt đất để trả về một cặp giá trị.

Thiết kế thay thế sẽ chuyển bộ sưu tập có thể thay đổi xuống với chức năng làm tham số và để điền vào bất kỳ thông báo lỗi nào muốn phát ra. Điều đó thường sẽ đơn giản hóa hệ thống ống nước trong người gọi, đặc biệt nếu có một số lớp cuộc gọi giữa trình phân tích cú pháp và mã biết cách thực hiện điều gì đó với thông báo lỗi sau đó.

+0

Câu cuối cùng của bạn - đó là một trong những lý do chính của tôi để tìm cách tốt hơn để làm điều này. Đã không nghĩ đến việc sử dụng 'tham số ngoài'. (Họ có một cái tên tốt hơn?) –

+0

Trong khi phát ra cảnh báo có thể đã được thanh lịch hơn trong một thế giới lý tưởng, thực tế là Jython chỉ lên đến 2,5 làm cho nó không thực tế đối với tôi. Tôi đã kết thúc một danh sách được lấp đầy bởi hàm phân tích cú pháp. Điều này làm việc đặc biệt tốt ở những nơi mà tôi gọi một vài hàm phân tích cú pháp khác nhau trong một hàng, và sau đó tôi có thể lặp qua toàn bộ danh sách cảnh báo khi chúng được thực hiện xong. Tôi thích điều này nhiều hơn là trả về các bộ dữ liệu và kiểm tra các giá trị trả về riêng biệt. –

+1

@CamJackson Dành cho các tình huống như thế này. Tôi đã thường xuyên tìm thấy rằng đi xuống một cuộc gọi lại với một chữ ký cuộc gọi cụ thể hoạt động tốt hơn so với đi qua một danh sách nguyên. Bằng cách đó, thật dễ dàng để trừu tượng hóa việc triển khai thực hiện từ bên trong, cũng như đặt lại một cuộc gọi lại khi người gọi không quan tâm để nhận lại lỗi. Thông thường, nó có thể đơn giản như truyền trong phương thức '.append' bị ràng buộc của danh sách bạn muốn thêm vào. Nó làm cho nó rõ ràng hơn rằng một cái gì đó đang được thông qua trở lại ("ra" params không phải là luôn luôn rõ ràng), và cho phép người gọi để xử lý phức tạp tại thời điểm lỗi. –

4

Emit a warning thay vào đó và để mã quyết định cách xử lý.

+0

thật dễ thương. không có ý tưởng rằng mô-đun tồn tại. có vẻ như cảnh báo có thể được kết nối với nhật ký của python, do đó có thể kết nối với gui. –

+0

Điều này có vẻ đầy hứa hẹn, hãy xem xét điều này ngay bây giờ. Chỉ có điều, tôi đang sử dụng Jython, mà dường như không có 'warnings.catch_warnings()', vì vậy tôi không chắc chắn làm thế nào tôi có nghĩa là để xử lý các cảnh báo. Tôi có thể thử bắt chúng như một ngoại lệ không? –

+0

Hmmm, tôi đọc qua [this] (http://www.jython.org/jythonbook/en/1.0/ExceptionHandlingDebug.html#issuing-warnings) nhưng nó không nói bất cứ điều gì về cách gọi hàm có thể nắm bắt các cảnh báo . Trừ khi tôi sử dụng một bộ lọc để biến cảnh báo thành trường hợp ngoại lệ, nhưng sau đó tôi trở lại nơi tôi bắt đầu không phải là tôi? Bạn có biết cách xử lý các cảnh báo mà không sử dụng 'catch_warnings()'? –

0

Tôi đến từ thế giới Net, vì vậy không chắc chắn cách này chuyển thành Python ...

Trong những trường hợp như của bạn (nơi bạn muốn xử lý nhiều mục trong một cuộc gọi duy nhất) Tôi muốn trả lại một MyProcessingResults đối tượng chứa hai bộ sưu tập, ví dụ:

  • MyProcessingResults.ProcessedLines - giữ tất cả dữ liệu hợp lệ bạn đã phân tích cú pháp.
  • MyProcessingResults.Errors - giữ tất cả các lỗi (với giả thiết rằng bạn có nhiều lỗi và bạn muốn biết rõ ràng về tất cả chúng).
+2

Âm thanh như thế này sẽ giống như việc trả lại một bộ các kết quả và bất kỳ lỗi nào. Trong python một tuple có thể chứa các đối tượng của các kiểu khác nhau, vì vậy không cần phải định nghĩa một lớp có chứa 2 đối tượng mà tôi muốn trả về nếu đó là cách tôi muốn làm. –

1

Một thiết kế khác có thể là đảo ngược kiểm soát, bằng cách chuyển trình xử lý lỗi vào làm tham số.

(Ngoài ra, không có cảm giác như bạn phải nói với Python làm thế nào để tích lũy dữ liệu trong danh sách. Nó biết rồi. Nó không khó để thực hiện một công việc danh sách hiểu ở đây.)

def sample_handler(): 
    print "OMG, I wasn't expecting that; oh well." 

parseResult = parse(myFile, sample_handler) 

def parse(file, handler): #file is a list of lines from an actual file 
    result = [Process(line) for line in data] 
    if not all(result): handler() # i.e. if there are any false-ish values 
    result = filter(None, result) # remove false-ish values if any 
    return result 
+0

Định dạng tệp dữ liệu của tôi phức tạp hơn một chút so với khi tôi bật, vì vậy tôi thực sự phải lặp qua danh sách theo cách thủ công, nhưng đó là một phương pháp hay. Python đầy những bất ngờ thú vị! –

1

Tùy thuộc vào thiết kế người gọi. sử dụng gọi lại có thể hợp lý:

def got_line(line): 
    print 'Got valid line', line 

def got_error(error): 
    print 'got error', error 

def parse(file, line, error): 
    for lines in file: 
     processedLine = Process(line) 
     if not processedLine: 
      error(MyErrorClass("Something went wrong")) 
     else 
      line(processedLine) 


parse(some_file, got_line, got_error) 
1

Tôi muốn đề xuất giải pháp thay thế; sử dụng một lớp học.

class MyParser(object): 
    def __init__(self): 
     self.warnings = [] 

    def parse(self, file): 
     ... 

Bây giờ chức năng phân tích cú pháp có thể đặt cảnh báo thành danh sách warnings và người dùng có thể kiểm tra danh sách này nếu muốn.

Ngay sau khi chức năng của tôi bắt đầu trở nên tiên tiến hơn là chỉ "xử lý và trả về giá trị của tôi", tôi muốn cân nhắc sử dụng lớp học thay thế. Nó làm cho cụm lớn các mã liên quan thành một đối tượng và nó thường làm cho mã sạch hơn và sử dụng đơn giản hơn các hàm trả về các thông tin.

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