Mục đích sử dụng của else
mệnh đề tùy chọn của try
câu lệnh là gì?
Mục đích sử dụng của else
mệnh đề tùy chọn của try
câu lệnh là gì?
Câu trả lời:
Các câu lệnh trong else
khối được thực thi nếu thực thi rơi xuống dưới cùng của try
- nếu không có ngoại lệ. Thành thật mà nói, tôi chưa bao giờ tìm thấy một nhu cầu.
Tuy nhiên, Xử lý ngoại lệ ghi chú:
Việc sử dụng mệnh đề khác tốt hơn là thêm mã bổ sung vào mệnh đề try vì nó tránh vô tình bắt gặp một ngoại lệ không được nêu ra bởi mã được bảo vệ bởi lệnh thử ... ngoại trừ câu lệnh.
Vì vậy, nếu bạn có một phương pháp có thể, ví dụ, ném IOError
và bạn muốn bắt ngoại lệ, nhưng có một cách khác bạn muốn làm nếu thao tác đầu tiên thành công và bạn không muốn bắt IOError từ đó hoạt động đó, bạn có thể viết một cái gì đó như thế này:
try:
operation_that_can_throw_ioerror()
except IOError:
handle_the_exception_somehow()
else:
# we don't want to catch the IOError if it's raised
another_operation_that_can_throw_ioerror()
finally:
something_we_always_need_to_do()
Nếu bạn đặt another_operation_that_can_throw_ioerror()
sau operation_that_can_throw_ioerror
, except
cuộc gọi sẽ bắt lỗi thứ hai. Và nếu bạn đặt nó sau toàn bộ try
khối, nó sẽ luôn được chạy, và cho đến sau đó finally
. Cho else
phép bạn chắc chắn
finally
khối vàIOError
nó tăng lên không bị bắt ở đâyreturn
, continue
hoặc break
.
Có một lý do lớn để sử dụng else
- phong cách và khả năng đọc. Nói chung, nên giữ mã có thể gây ra ngoại lệ gần mã liên quan đến chúng. Ví dụ, so sánh những điều này:
try:
from EasyDialogs import AskPassword
# 20 other lines
getpass = AskPassword
except ImportError:
getpass = default_getpass
và
try:
from EasyDialogs import AskPassword
except ImportError:
getpass = default_getpass
else:
# 20 other lines
getpass = AskPassword
Cách thứ hai là tốt khi except
không thể quay lại sớm hoặc ném lại ngoại lệ. Nếu có thể, tôi đã có thể viết:
try:
from EasyDialogs import AskPassword
except ImportError:
getpass = default_getpass
return False # or throw Exception('something more descriptive')
# 20 other lines
getpass = AskPassword
Lưu ý: Trả lời được sao chép từ bản sao được đăng gần đây tại đây , do đó tất cả nội dung "AskPassword" này.
Một lần sử dụng: kiểm tra một số mã sẽ đưa ra một ngoại lệ.
try:
this_should_raise_TypeError()
except TypeError:
pass
except:
assert False, "Raised the wrong exception type"
else:
assert False, "Didn't raise any exception"
(Mã này nên được trừu tượng hóa thành một thử nghiệm chung hơn trong thực tế.)
Python thử-khác
Mục đích sử dụng của
else
mệnh đề tùy chọn của câu lệnh try là gì?
Mục đích sử dụng là có một bối cảnh để chạy nhiều mã hơn nếu không có trường hợp ngoại lệ nào được dự kiến sẽ được xử lý.
Bối cảnh này tránh vô tình xử lý các lỗi bạn không mong đợi.
Nhưng điều quan trọng để hiểu được điều kiện chính xác gây ra các khoản khác để chạy là, bởi vì return
, continue
và break
có thể làm gián đoạn dòng điều khiển đến else
.
Các else
tuyên bố chạy nếu có không có trường hợp ngoại lệ và nếu không bị gián đoạn bởi một return
, continue
hoặc break
tuyên bố.
Các tùy chọn
else
điều khoản được thực hiện nếu và khi kiểm soát chảy ra khỏi cuối củatry
khoản. *
(Thêm vào.) Và chú thích ghi:
* Hiện nay, kiểm soát “chảy ra khỏi cuối” ngoại trừ trong trường hợp của một ngoại lệ hoặc thực hiện một
return
,continue
hoặcbreak
tuyên bố.
Nó không yêu cầu ít nhất một mệnh đề trước trừ mệnh đề ( xem ngữ pháp ). Vì vậy, nó thực sự không phải là "thử-khác", đó là "thử ngoại trừ khác (cuối cùng)," với else
(và finally
) là tùy chọn.
Các Bài chỉ dẫn Python nói rõ về việc sử dụng dự định:
Câu lệnh try ... ngoại trừ có một mệnh đề khác tùy chọn, mà khi có mặt, phải tuân theo tất cả các mệnh đề ngoại trừ mệnh đề. Nó rất hữu ích cho mã phải được thực thi nếu mệnh đề try không đưa ra một ngoại lệ. Ví dụ:
for arg in sys.argv[1:]: try: f = open(arg, 'r') except IOError: print 'cannot open', arg else: print arg, 'has', len(f.readlines()), 'lines' f.close()
Việc sử dụng mệnh đề khác tốt hơn là thêm mã bổ sung vào mệnh đề try vì nó tránh vô tình bắt một ngoại lệ không được nêu ra bởi mã được bảo vệ bởi lệnh thử ... ngoại trừ câu lệnh.
else
so với mã theo try
khốiNếu bạn xử lý một lỗi, else
khối sẽ không chạy. Ví dụ:
def handle_error():
try:
raise RuntimeError('oops!')
except RuntimeError as error:
print('handled a RuntimeError, no big deal.')
else:
print('if this prints, we had no error!') # won't print!
print('And now we have left the try block!') # will print!
Và bây giờ,
>>> handle_error()
handled a RuntimeError, no big deal.
And now we have left the try block!
Thử ngoại trừ khác là tuyệt vời để kết hợp mô hình EAFP với gõ vịt :
try:
cs = x.cleanupSet
except AttributeError:
pass
else:
for v in cs:
v.cleanup()
Bạn có thể thấy mã ngây thơ này là tốt:
try:
for v in x.cleanupSet:
v.clenaup()
except AttributeError:
pass
Đây là một cách tuyệt vời để vô tình che giấu các lỗi nghiêm trọng trong mã của bạn. Tôi đánh máy dọn dẹp ở đó, nhưng AttributionError sẽ cho tôi biết đang bị nuốt. Tồi tệ hơn, điều gì sẽ xảy ra nếu tôi viết nó một cách chính xác, nhưng phương thức dọn dẹp đôi khi được thông qua một loại người dùng có thuộc tính sai, khiến nó âm thầm thất bại giữa chừng và để lại một tệp không được tiết lộ? Chúc may mắn gỡ lỗi đó.
Tôi thấy nó thực sự hữu ích khi bạn đã dọn dẹp để làm điều đó phải được thực hiện ngay cả khi có một ngoại lệ:
try:
data = something_that_can_go_wrong()
except Exception as e: # yes, I know that's a bad way to do it...
handle_exception(e)
else:
do_stuff(data)
finally:
clean_up()
Mặc dù bạn không thể nghĩ đến việc sử dụng nó ngay bây giờ, bạn có thể đặt cược rằng phải có một cách sử dụng nó. Đây là một mẫu không tưởng tượng:
Với else
:
a = [1,2,3]
try:
something = a[2]
except:
print "out of bounds"
else:
print something
Không có else
:
try:
something = a[2]
except:
print "out of bounds"
if "something" in locals():
print something
Ở đây bạn có biến something
được xác định nếu không có lỗi được ném. Bạn có thể loại bỏ cái này bên ngoài try
khối, nhưng sau đó nó yêu cầu một số phát hiện lộn xộn nếu một biến được xác định.
something = a[2]; print something
bên trong thử: khối?
Có một ví dụ tốt đẹp của try-else
trong PEP 380 . Về cơ bản, nó đi xuống để thực hiện xử lý ngoại lệ khác nhau trong các phần khác nhau của thuật toán.
Nó giống như thế này:
try:
do_init_stuff()
except:
handle_init_suff_execption()
else:
try:
do_middle_stuff()
except:
handle_middle_stuff_exception()
Điều này cho phép bạn viết mã xử lý ngoại lệ gần nơi xảy ra ngoại lệ.
Từ lỗi và ngoại lệ # Xử lý ngoại lệ - docs.python.org
Câu
try ... except
lệnh có mộtelse
mệnh đề tùy chọn , mà khi có mặt, phải tuân theo tất cả các mệnh đề ngoại trừ mệnh đề. Nó rất hữu ích cho mã phải được thực thi nếu mệnh đề try không đưa ra một ngoại lệ. Ví dụ:for arg in sys.argv[1:]: try: f = open(arg, 'r') except IOError: print 'cannot open', arg else: print arg, 'has', len(f.readlines()), 'lines' f.close()
Việc sử dụng mệnh đề khác tốt hơn là thêm mã bổ sung vào mệnh đề try vì nó tránh vô tình bắt một ngoại lệ không được nêu ra bởi mã được bảo vệ bởi lệnh thử ... ngoại trừ câu lệnh.
Nhìn vào tài liệu tham khảo Python có vẻ như else
được thực thi sau try
khi không có ngoại lệ. Mệnh đề khác tùy chọn được thực thi nếu và khi điều khiển chảy ra khỏi cuối mệnh đề try. 2 Các ngoại lệ trong mệnh đề khác không được xử lý bởi các mệnh đề trước trừ các mệnh đề.
Đi sâu vào python có một ví dụ trong đó, nếu tôi hiểu chính xác, trong try
khối họ cố gắng nhập một mô-đun, khi đó bạn không có ngoại lệ và liên kết mặc định nhưng khi nó hoạt động, bạn có một tùy chọn để đi vào else
khối và liên kết những gì được yêu cầu (xem liên kết cho ví dụ và giải thích).
Nếu bạn cố gắng thực hiện công việc trong catch
khối, nó có thể đưa ra một ngoại lệ khác - tôi đoán đó là nơi mà else
khối này có ích.
try
khối.
Đó là nó. Khối 'khác' của mệnh đề ngoại trừ thử tồn tại cho mã chạy khi (và chỉ khi) hoạt động đã thử thành công. Nó có thể được sử dụng, và nó có thể bị lạm dụng.
try:
fp= open("configuration_file", "rb")
except EnvironmentError:
confdata= '' # it's ok if the file can't be opened
else:
confdata= fp.read()
fp.close()
# your code continues here
# working with (possibly empty) confdata
Cá nhân, tôi thích nó và sử dụng nó khi thích hợp. Nó ngữ nghĩa nhóm các tuyên bố.
Có lẽ một cách sử dụng có thể là:
#debug = []
def debuglog(text, obj=None):
" Simple little logger. "
try:
debug # does global exist?
except NameError:
pass # if not, don't even bother displaying
except:
print('Unknown cause. Debug debuglog().')
else:
# debug does exist.
# Now test if you want to log this debug message
# from caller "obj"
try:
if obj in debug:
print(text) # stdout
except TypeError:
print('The global "debug" flag should be an iterable.')
except:
print('Unknown cause. Debug debuglog().')
def myfunc():
debuglog('Made it to myfunc()', myfunc)
debug = [myfunc,]
myfunc()
Có lẽ điều này sẽ dẫn bạn quá sử dụng.
Tôi đã tìm thấy try: ... else:
cấu trúc hữu ích trong trường hợp bạn đang chạy các truy vấn cơ sở dữ liệu và ghi lại kết quả của các truy vấn đó vào một cơ sở dữ liệu riêng biệt có cùng loại / hương vị. Giả sử tôi có rất nhiều luồng công nhân tất cả các xử lý truy vấn cơ sở dữ liệu được gửi đến hàng đợi
#in a long running loop
try:
query = queue.get()
conn = connect_to_db(<main db>)
curs = conn.cursor()
try:
curs.execute("<some query on user input that may fail even if sanitized">)
except DBError:
logconn = connect_to_db(<logging db>)
logcurs = logconn.cursor()
logcurs.execute("<update in DB log with record of failed query")
logcurs.close()
logconn.close()
else:
#we can't put this in main try block because an error connecting
#to the logging DB would be indistinguishable from an error in
#the mainquery
#We can't put this after the whole try: except: finally: block
#because then we don't know if the query was successful or not
logconn = connect_to_db(<logging db>)
logcurs = logconn.cursor()
logcurs.execute("<update in DB log with record of successful query")
logcurs.close()
logconn.close()
#do something in response to successful query
except DBError:
#This DBError is because of a problem with the logging database, but
#we can't let that crash the whole thread over what might be a
#temporary network glitch
finally:
curs.close()
conn.close()
#other cleanup if necessary like telling the queue the task is finished
Tất nhiên, nếu bạn có thể phân biệt giữa các ngoại lệ có thể bị ném, bạn không phải sử dụng điều này, nhưng nếu mã phản ứng với một đoạn mã thành công có thể ném ngoại lệ giống như đoạn thành công và bạn không thể chỉ hãy để ngoại lệ thứ hai có thể xảy ra, hoặc quay trở lại ngay lập tức khi thành công (sẽ giết chết chuỗi trong trường hợp của tôi), sau đó điều này sẽ có ích.
Một else
khối thường có thể tồn tại để bổ sung cho chức năng xảy ra trong mọi except
khối.
try:
test_consistency(valuable_data)
except Except1:
inconsistency_type = 1
except Except2:
inconsistency_type = 2
except:
# Something else is wrong
raise
else:
inconsistency_type = 0
"""
Process each individual inconsistency down here instead of
inside the except blocks. Use 0 to mean no inconsistency.
"""
Trong trường hợp này, inconsistency_type
được đặt trong mỗi khối ngoại trừ, để hành vi được bổ sung trong trường hợp không có lỗi trong else
.
Tất nhiên, tôi mô tả điều này như một mô hình có thể xuất hiện trong mã của riêng bạn một ngày nào đó. Trong trường hợp cụ thể này, bạn chỉ cần đặt inconsistency_type
thành 0 trước try
khối.
Đây là một nơi khác mà tôi thích sử dụng mẫu này:
while data in items:
try
data = json.loads(data)
except ValueError as e:
log error
else:
# work on the `data`
continue
thay thế - mô hình "thoát ra sớm". Điều này cho phép bạn bỏ mệnh đề "other" và thụt lề của nó, làm cho mã dễ đọc hơn.
Một trong những tình huống sử dụng tôi có thể nghĩ đến là các ngoại lệ không thể đoán trước, có thể tránh được nếu bạn thử lại. Chẳng hạn, khi các hoạt động trong khối thử bao gồm các số ngẫu nhiên:
while True:
try:
r = random.random()
some_operation_that_fails_for_specific_r(r)
except Exception:
continue
else:
break
Nhưng nếu ngoại lệ có thể được dự đoán, bạn nên luôn luôn chọn xác nhận trước một ngoại lệ. Tuy nhiên, không phải mọi thứ đều có thể dự đoán được, vì vậy mẫu mã này có vị trí của nó.
break
bên trong try
ở cuối, IMO sạch hơn và bạn không cần else
. Ngoài ra, continue
không thực sự cần thiết, bạn có thể chỉ pass
.
Tôi đã tìm thấy else
hữu ích để xử lý một tệp cấu hình có thể không chính xác:
try:
value, unit = cfg['lock'].split()
except ValueError:
msg = 'lock monitoring config must consist of two words separated by white space'
self.log('warn', msg)
else:
# get on with lock monitoring if config is ok
Một ngoại lệ đọc lock
cấu hình sẽ vô hiệu hóa giám sát khóa và ValueErrors ghi lại một thông báo cảnh báo hữu ích.
Tôi sẽ thêm một trường hợp sử dụng khác có vẻ đơn giản khi xử lý các phiên DB:
# getting a DB connection
conn = db.engine.connect()
# and binding to a DB session
session = db.get_session(bind=conn)
try:
# we build the query to DB
q = session.query(MyTable).filter(MyTable.col1 == 'query_val')
# i.e retrieve one row
data_set = q.one_or_none()
# return results
return [{'col1': data_set.col1, 'col2': data_set.col2, ...}]
except:
# here we make sure to rollback the transaction,
# handy when we update stuff into DB
session.rollback()
raise
else:
# when no errors then we can commit DB changes
session.commit()
finally:
# and finally we can close the session
session.close()
Các else:
khối là khó hiểu và (gần như) vô dụng. Nó cũng là một phần của for
vàwhile
tuyên bố.
Trên thực tế, ngay cả trên một tầng lớp if
,else:
có thể bị lạm dụng theo những cách thực sự khủng khiếp tạo ra những lỗi rất khó tìm.
Xem xét điều này.
if a < 10:
# condition stated explicitly
elif a > 10 and b < 10:
# condition confusing but at least explicit
else:
# Exactly what is true here?
# Can be hard to reason out what condition is true
Hãy suy nghĩ kỹ về else:
. Nó thường là một vấn đề. Tránh nó ngoại trừ trong một if
-statement và thậm chí sau đó xem xét ghi lại else
điều kiện - để làm cho nó rõ ràng.
if x > 0: return "yes"
và if x <= 0: return "no"
. Bây giờ một người đến và thay đổi một trong những điều kiện để nói x > 1
nhưng quên thay đổi một điều kiện khác. Làm thế nào là giảm số lượng lỗi sẽ được cam kết. if else
mệnh đề đôi khi cách nhau nhiều dòng. DRY là một thực hành tốt, thường xuyên hơn không, thực sự. (Xin lỗi cho đăng bài gấp đôi).