Sử dụng câu lệnh python “with” với khối try-exception


96

Đây có phải là cách phù hợp để sử dụng câu lệnh python "with" kết hợp với khối try-exception không ?:

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

Nếu đúng, hãy 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 "with" ở đây là chúng ta có thể loại bỏ ba dòng mã? Nó có vẻ không hấp dẫn đối với tôi đối với trường hợp sử dụng này (mặc dù tôi hiểu rằng câu lệnh "with" có những cách sử dụng khác).

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

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



Đối với tôi, không cần phải nhớ đóng () những thứ trong câu lệnh cuối cùng là một lý do đủ tốt để sử dụng 'with'. Tôi đã thấy rất nhiều mã không đóng được tài nguyên của nó. Và 'with' không có nhược điểm theo như tôi thấy.
Raúl Salinas-Monteagudo

Câu trả lời:


139
  1. Hai khối mã bạn đã cung cấp không tương đương
  2. Đoạn mã mà bạn mô tả là cách làm cũ có một lỗi nghiêm trọng: trong trường hợp mở tệp không thành công, bạn sẽ nhận được ngoại lệ thứ hai trong finallymệnh đề vì fkhông bị ràng buộc.

Mã kiểu cũ tương đương sẽ là:

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

Như bạn thấy, withcâu lệnh có thể làm cho mọi thứ ít bị lỗi hơn. Trong các phiên bản Python mới hơn (2.7, 3.1), bạn cũng có thể kết hợp nhiều biểu thức trong một withcâu lệnh. 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 việc bắt bất kỳ ngoại lệ nào càng sớm càng tốt là một thói quen xấu. Đây không phải là mục đích của các trường hợp ngoại lệ. Nếu chức năng IO có thể bị lỗ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ác withcâu lệnh, bạn có thể loại bỏ tất cả các try...finallycâu lệnh này ở cấp độ bên trong.


7

Nếu nội dung của finallykhối đượ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à người ghi finallykhối? Đó là lợi ích của withcâu lệnh, nhiều hơn là tiết kiệm cho bạn ba dòng mã trong trường hợp cụ thể này.

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


1

Tôi nghĩ rằng bạn đã hiểu sai về câu lệnh "with" rằng nó chỉ làm giảm dòng. 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ở tệp tin,
  • xử lý nội dung của nó, và
  • đảm bảo đóng nó.

Đây là liên kết để hiểu câu lệnh "with": http://effbot.org/zone/python-with-statement.htm

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


-4

Cách Pythonic nhiều hơn cho các mã sau 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()

1
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 việc thụt lề.
andrewsi

2
Không, phiên bản của bạn không làm điều tương tự như mã gốc. Ngay cả khi bạn thêm readline()cuộc gọi bị thiếu , phiên bản của bạn không đóng tệp nếu readline()kết quả là IOError.
Aleksi Torhamo
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.