2010-09-04 41 views
74

Đây có phải là cách đúng đắn để sử dụng python "với" tuyên bố kết hợp với một thử-trừ khối ?:Sử dụng python "với" tuyên bố với thử-trừ khối

try: 
    with open("file", "r") as f: 
     line = f.readline() 
except IOError: 
    <whatever> 

Nếu nó được, sau đó xem xét cách làm cũ:

try: 
    f = open("file", "r") 
    line = f.readline() 
except IOError: 
    <whatever> 
finally: 
    f.close() 

Lợi ích chính của câu lệnh "có" ở đây là chúng ta có thể loại bỏ ba dòng mã? Nó không có vẻ hấp dẫn đối với tôi cho trường hợp sử dụng này (mặc dù tôi hiểu rằng câu lệnh "có" có các mục đích sử dụng khác).

CHỈNH SỬA: Chức năng của hai khối mã trên giống hệt nhau không?

EDIT2: Một vài câu trả lời đầu tiên nói chung về lợi ích của việc sử dụng "bằng", nhưng những câu hỏi đó có vẻ như có lợi ích cận biên ở đây. Tất cả chúng ta đều (hoặc lẽ ra phải) đã gọi rõ ràng f.close() trong nhiều năm. Tôi cho rằng một lợi ích là các lập trình viên cẩu thả sẽ được hưởng lợi từ việc sử dụng "với".

+0

có thể trùng lặp của [Bắt một ngoại lệ khi sử dụng Python 'với' tuyên bố] (http://stackoverflow.com/questions/713794/catching -an-exception-while-using-a-python-with-statement) –

Trả lời

112
  1. Hai khối mã bạn đã được không tương đương
  2. Mã bạn mô tả như cách cũ làm việc có một lỗi nghiêm trọng: trong trường hợp mở các tập tin bị lỗi bạn sẽ nhận được ngoại lệ thứ hai trong điều khoản finallyf không phải là bị ràng buộc.

Mã tương đương phong cách cũ sẽ là:

try: 
    f = open("file", "r") 
    try: 
     line = f.readline() 
    finally: 
     f.close() 
except IOError: 
    <whatever> 

Như bạn thấy, báo cáo kết quả with có thể làm cho mọi việc ít dễ bị lỗi. Trong các phiên bản mới hơn của Python (2.7, 3.1), bạn cũng có thể kết hợp nhiều biểu thức trong một câu lệnh with. Ví dụ:

with open("input", "r") as inp, open("output", "w") as out: 
    out.write(inp.read()) 

Bên cạnh đó, cá nhân tôi coi thói quen xấu là bắt bất kỳ ngoại lệ nào càng sớm càng tốt. Đây không phải là mục đích của ngoại lệ. Nếu hàm IO có thể thất bại là một phần của một hoạt động phức tạp hơn, trong hầu hết các trường hợp, IOError sẽ hủy bỏ toàn bộ hoạt động và do đó được xử lý ở cấp độ bên ngoài. Sử dụng câu lệnh with, bạn có thể loại bỏ tất cả các câu lệnh try...finally này ở cấp độ bên trong.

6

Nếu nội dung của khối finally được xác định bởi các thuộc tính của đối tượng tệp đang được mở, tại sao người triển khai đối tượng tệp không phải là đối tượng để viết khối finally? Đó là lợi ích của tuyên bố with, nhiều hơn việc tiết kiệm cho bạn ba dòng mã trong trường hợp cụ thể này.

Và vâng, theo cách mà bạn đã kết hợp withtry-except là khá nhiều cách duy nhất để làm điều đó, như các lỗi đặc biệt gây ra trong báo cáo kết quả open bản thân nó không thể được đánh bắt trong khối with.

1

Tôi nghĩ bạn đã hiểu sai về tuyên bố "có" rằng nó chỉ làm giảm đường kẻ. Nó thực sự khởi tạo và xử lý teardown.

Trong trường hợp của bạn "với" không

  • mở một tập tin,
  • quá trình nội dung của nó, và
  • hãy chắc chắn để đóng nó lại.

Dưới đây là liên kết cho sự hiểu biết "với" tuyên bố: http://effbot.org/zone/python-with-statement.htm

Edit: Có việc bạn sử dụng "với" là đúng và chức năng của cả hai khối mã là giống hệt nhau. Câu hỏi về lý do sử dụng "bằng"? đó là vì lợi ích bạn nhận được với nó. giống như bạn đã đề cập về việc vô tình thiếu f.close().

-3

Cách Pythonic hơn cho các mã sau đây là:

try: 
    f = open("file", "r") 
    try: 
     line = f.readline() 
    finally: 
     f.close() 
except IOError: 
    <whatever> 

try: 
    f = open("file", "r") 
except IOError: 
    <whatever> 
else: 
    f.close() 
+0

Tôi đã thêm định dạng mã cho bạn; nó làm cho nó dễ đọc hơn. Nhưng bạn có thể muốn kiểm tra lại để đảm bảo rằng tôi đã không làm hỏng thụt lề. – andrewsi

+0

Không, phiên bản của bạn không làm giống như mã gốc. Ngay cả khi bạn thêm lệnh 'readline()' bị thiếu, phiên bản của bạn không đóng tệp nếu kết quả 'readline()' trong một 'IOError'. –

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