2011-10-15 5 views
31
# Open new file to write 
file = None 
try: 
    file = open(filePath, 'w') 
except IOError: 
    msg = ("Unable to create file on disk.") 
    file.close() 
    return 
finally: 
    file.write("Hello World!") 
    file.close() 

Đoạn mã trên được tách khỏi một hàm. Một trong những hệ thống của người dùng được thông báo một lỗi trong dòng:python try: except: finally:

file.write("Hello World!") 

lỗi:

AttributeError: 'NoneType' object has no attribute 'write' 

Câu hỏi là, Nếu trăn đang thất bại trong việc mở tập tin nhất định, 'trừ' thực thi khối và nó phải trở lại, nhưng kiểm soát là nhận được chuyển giao cho dòng đó là ném lỗi nhất định. Giá trị của biến 'tệp' là 'Không'.

Mọi con trỏ?

Trả lời

67

Bạn không nên ghi vào tệp trong khối finally vì bất kỳ ngoại lệ nào được nêu ra sẽ không bị chặn bởi khối except.

Đoạn mã except thực hiện nếu có một ngoại lệ được khối try thử đưa ra. Các khối finallyluôn luôn thực thi bất kỳ điều gì xảy ra.

Ngoài ra, không cần thiết phải khởi tạo biến số file thành none.

Việc sử dụng return trong khối except sẽ không bỏ qua khối finally. Bởi bản chất của nó, nó không thể bỏ qua, đó là lý do tại sao bạn muốn đặt mã "dọn dẹp" của bạn trong đó (tức là đóng các tệp).

Vì vậy, nếu bạn muốn sử dụng thử: trừ: cuối cùng, bạn nên làm một cái gì đó như thế này:

try: 
    f = open("file", "w") 
    try: 
     f.write('Hello World!') 
    finally: 
     f.close() 
except IOError: 
    print 'oops!' 

Một cách sạch hơn để làm điều này là sử dụng with tuyên bố:

try: 
    with open("output", "w") as outfile: 
     outfile.write('Hello World') 
except IOError: 
    print 'oops!' 
+11

+1 cho 'tuyên bố with' – gecco

+0

mã là rất clever.i học hỏi từ nó – viprs

+1

Thật không may,' with' là không có mặt trong python 2.4, vì vậy nó sẽ không hoạt động. – SummerBreeze

0

cuối cùng luôn được gọi trong "kết thúc", ngay cả khi một ocurrs ngoại lệ. Bạn có thể sử dụng điều này để đảm bảo tài nguyên mở được đóng (ví dụ: kết nối DB, tệp, v.v.).

Tôi nghĩ bạn hiểu nhầm ngữ nghĩa.

Logic của bạn phải nằm trong "thử", bạn nên xử lý ngoại lệ trong khối "ngoại trừ" và "cuối cùng" thực hiện bất kể phương thức của bạn chấm dứt, sử dụng nó để dọn sạch.

1

ngoại trừ không thực hiện (vì loại là IOError) đó là phần cuối cùng mà ném một lỗi khác của kiểu AttributeError vì tệp = Không.

27

Nếu tệp không được mở, dòng file = open(filePath, 'w') không thành công, vì vậy không có gì được gán cho file.

Sau đó, mệnh đề except chạy, nhưng không có gì trong tệp, do đó file.close() không thành công.

Điều khoản finally luôn chạy, ngay cả khi có ngoại lệ. Và kể từ file vẫn là Không, bạn có ngoại lệ khác.

Bạn muốn mệnh đề else thay vì finally cho những điều chỉ xảy ra nếu không có ngoại lệ.

try: 
     file = open(filePath, 'w') 
    except IOError: 
     msg = "Unable to create file on disk." 
     return 
    else: 
     file.write("Hello World!") 
     file.close() 

Tại sao else? Các Python docs nói:

The use of the else clause is better than adding additional code to the try clause because it avoids accidentally catching an exception that wasn’t raised by the code being protected by the try ... except statement.

Nói cách khác, điều này sẽ không bắt một IOError từ write hoặc close cuộc gọi. Đó là tốt, bởi vì sau đó lý do woudn't đã được "Không thể tạo tập tin trên đĩa." - nó sẽ có được một lỗi khác nhau, một trong những mã của bạn đã không được chuẩn bị cho. Đó là một ý tưởng hay để không xử lý các lỗi như vậy.

+1

+1 cho mục chưa sử dụng 'else' – kindall

+0

Nhưng điều gì sẽ xảy ra nếu tệp tin.write() tăng ngoại lệ - hoàn toàn có thể sau khi mở, thậm chí mặc dù nó đã được mở bằng quyền ghi. Tốt nhất để bao gồm trong thử: block – jenming

+1

@ jenming: Vâng, khá nhiều bất cứ điều gì có thể nâng cao ngoại lệ :) Bạn thực sự nên cố gắng chỉ xử lý các trường hợp ngoại lệ bạn mong đợi, mặc dù. Nếu bạn lo lắng về các ngoại lệ từ 'file.write()', hãy đưa nó vào 'try'; chỉ cần chắc chắn không bao gồm một cái gì đó như 'file.write (" kết quả:% s "% do_calculation())', vì nó sẽ ẩn các ngoại lệ từ 'do_calculation'. –

3

logic trong đó có

file.write("Hello World!")

bên trong mệnh đề finally là gì ?? tôi nghĩ rằng nó phải được đặt trong mệnh đề try.

try: 
     file = open(filePath, 'w') 
     file.write("Hello World!") 
except IOError: 
     print("Unable to create file on disk.") 
finally: 
     file.close() 
0

Bạn nên viết logic hoặc mã có thể ném ngoại lệ vào khối thử và sử dụng khối cuối cùng để đóng tài nguyên.

+0

Không liên quan đến câu hỏi ban đầu. – stackoverflowuser2010

1

Bạn có thể làm một cái gì đó như thế này:

try: 
    do_some_stuff() 
finally: 
    cleanup_stuff() 
1

Dưới đây là giải pháp trực tiếp nhất cho vấn đề của bạn. Tôi sử dụng thành ngữ kiểm tra cho file_obj != None trong khối finally.

Nhân tiện, bạn nên lưu ý rằng file là tên lớp Python, vì vậy bạn nên chọn tên biến khác.

file = None 
try: 
    file = open(filePath, 'w') 
except IOError: 
    msg = ("Unable to create file on disk.") 
    file.close() 
    return 
finally: 
    if file != None: 
     file.write("Hello World!") 
     file.close()