Yanıtlar:
Python'da manuel olarak nasıl bir istisna atarım / yükseltirim?
Sorununuza anlamsal olarak uyan en özel İstisna yapıcısını kullanın .
Mesajınızda açık olun, örneğin:
raise ValueError('A very specific bad thing happened.')
Jenerik yetiştirmekten kaçının Exception
. Onu yakalamak için, onu sınıflandıran diğer tüm özel istisnaları yakalamanız gerekir.
raise Exception('I know Python!') # Don't! If you catch, likely to hide bugs.
Örneğin:
def demo_bad_catch():
try:
raise ValueError('Represents a hidden bug, do not catch this')
raise Exception('This is the exception you expect to handle')
except Exception as error:
print('Caught this error: ' + repr(error))
>>> demo_bad_catch()
Caught this error: ValueError('Represents a hidden bug, do not catch this',)
Ve daha özel yakalamalar genel istisnayı yakalamaz:
def demo_no_catch():
try:
raise Exception('general exceptions not caught by specific handling')
except ValueError as e:
print('we will not catch exception: Exception')
>>> demo_no_catch()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 3, in demo_no_catch
Exception: general exceptions not caught by specific handling
raise
açıklamaBunun yerine, sorununuza anlamsal olarak uyan en özel İstisna yapıcısını kullanın .
raise ValueError('A very specific bad thing happened')
ayrıca, kurucuya rasgele sayıda argümanın iletilmesini de sağlar:
raise ValueError('A very specific bad thing happened', 'foo', 'bar', 'baz')
Bu bağımsız değişkenlere nesnenin args
özniteliği tarafından erişilir Exception
. Örneğin:
try:
some_code_that_may_raise_our_value_error()
except ValueError as err:
print(err.args)
baskılar
('message', 'foo', 'bar', 'baz')
Python 2.5'te, kullanıcıları İstisnaları alt sınıfa aktarmaya ve kullanmayı bırakmaya teşvik etmek için gerçek bir message
özellik eklendi , ancak argümanların tanıtılması ve orijinal kullanımdan kaldırılması geri çekildi .BaseException
args
message
except
yan tümcesiDışlama yantümcesinin içindeyken, örneğin, belirli bir hata türünün oluştuğunu günlüğe kaydetmek ve ardından yeniden yükseltmek isteyebilirsiniz. Yığın izini korurken bunu yapmanın en iyi yolu çıplak yükseltme deyimi kullanmaktır. Örneğin:
logger = logging.getLogger(__name__)
try:
do_something_in_app_that_breaks_easily()
except AppError as error:
logger.error(error)
raise # just this!
# raise AppError # Don't do this, you'll lose the stack trace!
Yığın izini (ve hata değerini) ile koruyabilirsiniz sys.exc_info()
, ancak bu daha fazla hataya yatkındır ve Python 2 ve 3 arasında uyumluluk sorunları vardır , raise
yeniden yükseltmek için çıplak kullanmayı tercih edin .
Açıklamak için - sys.exc_info()
tür, değer ve geri izleme döndürür.
type, value, traceback = sys.exc_info()
Bu Python 2'deki sözdizimidir - bunun Python 3 ile uyumlu olmadığını unutmayın:
raise AppError, error, sys.exc_info()[2] # avoid this.
# Equivalently, as error *is* the second object:
raise sys.exc_info()[0], sys.exc_info()[1], sys.exc_info()[2]
İsterseniz, yeni yükseltmenizde ne olacağını değiştirebilirsiniz - örneğin args
, örnek için yeni ayar yapmak:
def error():
raise ValueError('oops!')
def catch_error_modify_message():
try:
error()
except ValueError:
error_type, error_instance, traceback = sys.exc_info()
error_instance.args = (error_instance.args[0] + ' <modification>',)
raise error_type, error_instance, traceback
Argleri değiştirirken tüm izleri koruduk. Bunun en iyi uygulama olmadığını ve Python 3'te geçersiz sözdizimi olduğunu unutmayın (uyumluluğun daha fazla çalışmasını zorlaştırır).
>>> catch_error_modify_message()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 3, in catch_error_modify_message
File "<stdin>", line 2, in error
ValueError: oops! <modification>
In Python 3 :
raise error.with_traceback(sys.exc_info()[2])
Tekrar: Geri izlemeleri manuel olarak manipüle etmekten kaçının. Daha az verimli ve hataya daha yatkındır. Eğer diş çekme kullanıyorsanız ve sys.exc_info
yanlış geri izleme bile alabilirsiniz (özellikle kontrol akışı için istisna işleme kullanıyorsanız - ki bu şahsen kaçınmaya eğilimliydim.)
Python 3'te, geri izleri koruyan İstisnaları zincirleyebilirsiniz:
raise RuntimeError('specific message') from error
Farkında olmak:
Bunlar kolayca gizlenebilir ve hatta üretim koduna girebilir. Bir istisna oluşturmak istiyorsunuz ve bunları yapmak bir istisna yaratacaktır, ancak amaçlananı değil!
Python 2'de geçerlidir, ancak Python 3'te geçerli değildir :
raise ValueError, 'message' # Don't do this, it's deprecated!
Sadece Python'un (2.4 ve daha eski) çok eski sürümlerinde geçerlidir , yine de dizeleri yükselten insanları görebilirsiniz:
raise 'message' # really really wrong. don't do this.
Tüm modern versiyonlarda, bu aslında bir artıracaktır TypeError
, çünkü bir BaseException
tür yetiştirmiyorsunuz . Doğru istisnayı kontrol etmiyorsanız ve sorunun farkında olan bir yorumcunuz yoksa, üretime geçebilir.
Yanlış kullandıkları takdirde tüketicilerimi API'm konusunda uyarmak için İstisnalar oluşturuyorum:
def api_func(foo):
'''foo should be either 'baz' or 'bar'. returns something very useful.'''
if foo not in _ALLOWED_ARGS:
raise ValueError('{foo} wrong, use "baz" or "bar"'.format(foo=repr(foo)))
"Amaç dışında bir hata yapmak istiyorum, böylece dışına girecek"
Kendi hata türlerinizi oluşturabilirsiniz, uygulamanızla ilgili belirli bir şeyin yanlış olduğunu belirtmek istiyorsanız, istisna hiyerarşisinde uygun noktayı alt sınıfta tutmanız yeterlidir:
class MyAppLookupError(LookupError):
'''raise this when there's a lookup error for my app'''
ve kullanım:
if important_key not in resource_dict and not ok_to_be_missing:
raise MyAppLookupError('resource is missing, and that is not ok.')
raise sys.exc_info()[0], (sys.exc_info()[1], my_extra_info), sys.exc_info()[2]
istediğimi yapıyor gibi görünüyor ve ben onunla hiçbir zaman sorunla karşılaşmadım. Ama kabul edilebilir bir uygulama değil, acayip hissediyor. Daha iyi bir yol var mı?
Exception
ana sınıfınız olarak türetilmeyen 4 istisnadan birini kullanmamanız gerektiği anlamına gelir - daha spesifik bir şeyi alt sınıflandırabilirsiniz ve eğer mantıklıysa bunu yapmalısınız.
AppError
istisna kullanırsınız. Gibi yerleşik bir hata kullanmak daha iyi olabilirAttributeError
BUNU YAPMAYIN . Çıplak yetiştirmek
Exception
kesinlikle doğru bir şey değildir ; Aaron Hall'ın mükemmel cevabına bakın .
Bundan daha fazla pitonik olamaz:
raise Exception("I know python!")
Daha fazla bilgi istiyorsanız, python için zam bildirimi belgelerine bakın .
Python3'te istisnaları istisna etmek için 4 farklı sözdizimi vardır:
1. raise exception
2. raise exception (args)
3. raise
4. raise exception (args) from original_exception
1. istisna uyandırmak vs. 2. istisna ulaştırmak (argümanlar)
Bir raise exception (args)
istisnayı yükseltmek için args
kullanırsanız, istisna nesnesini yazdırdığınızda bu istisna yazdırılır - aşağıdaki örnekte gösterildiği gibi.
#raise exception (args)
try:
raise ValueError("I have raised an Exception")
except ValueError as exp:
print ("Error", exp) # Output -> Error I have raised an Exception
#raise execption
try:
raise ValueError
except ValueError as exp:
print ("Error", exp) # Output -> Error
3.raise
raise
herhangi bir argüman olmadan ifade son istisnayı yeniden gündeme getirir. Bu, istisnayı yakaladıktan sonra bazı eylemleri gerçekleştirmeniz ve ardından yeniden yükseltmek istiyorsanız kullanışlıdır. Ancak daha önce bir istisna yoksa, raise
ifade İstisna'yı yükseltir TypeError
.
def somefunction():
print("some cleaning")
a=10
b=0
result=None
try:
result=a/b
print(result)
except Exception: #Output ->
somefunction() #some cleaning
raise #Traceback (most recent call last):
#File "python", line 8, in <module>
#ZeroDivisionError: division by zero
4. original_exception istisnasını (argümanlar) yükseltin
Bu ifade, başka bir istisnaya yanıt olarak ortaya konan bir istisnanın, aşağıdaki istisnada gösterildiği gibi orijinal istisnanın ayrıntılarını içerebileceği istisna zincirlemesi oluşturmak için kullanılır.
class MyCustomException(Exception):
pass
a=10
b=0
reuslt=None
try:
try:
result=a/b
except ZeroDivisionError as exp:
print("ZeroDivisionError -- ",exp)
raise MyCustomException("Zero Division ") from exp
except MyCustomException as exp:
print("MyException",exp)
print(exp.__cause__)
Çıktı:
ZeroDivisionError -- division by zero
MyException Zero Division
division by zero
exception(args)
aşkınexception (args)
raise exception(args) from None
şu anda aktif olan istisnanın ele alındığını ve artık ilgilenilmediğini söylemek gerekir. Aksi takdirde, bir except
blok içinde bir istisna yükseltir ve işlenmezse, her iki istisna için izlemeler, “Yukarıdaki istisnanın işlenmesi sırasında başka bir istisna oluştu” mesajıyla ayrılmış olarak gösterilir
Bazı beklenmedik koşullara yanıt olarak bir istisna atmanız gereken ve asla yakalamayı düşünmediğiniz, ancak o zaman hata ayıklamanıza izin vermek için hızlı bir şekilde başarısız olmanız gereken en yaygın durum - en mantıklı olan gibi görünüyor AssertionError
:
if 0 < distance <= RADIUS:
#Do something.
elif RADIUS < distance:
#Do something.
else:
raise AssertionError("Unexpected value of 'distance'!", distance)
ValueError
daha iyi bir durumdur AssertionError
- sorun bir değerde. AssertionError
Bu durumda gerçekten bir istiyorsanız , yazın assert distance > 0, 'Distance must be positive'
. Ancak bu şekilde hata kontrol etmemelisiniz çünkü iddialar kapatılabilir ( python -O
).
-O
.
Önce mevcut cevapları okuyun, bu sadece bir zeyilname.
Bağımsız değişkenli veya bağımsız değişkenli özel durumlar oluşturabileceğinize dikkat edin.
Misal:
raise SystemExit
programdan çıkar ancak ne olduğunu bilmek isteyebilirsiniz.
raise SystemExit("program exited")
program kapatılmadan önce stderr'a "programdan çıkıldı" yazdıracaktır.
raise SystemExit()
iyi bir seçim olmaz mıydı? İlki neden çalışıyor?
İstisnalar atmanın bir başka yolu da assert
. Bir koşulun yerine getirilip getirilmediğini doğrulamak için assert kullanabilirsiniz AssertionError
. Daha fazla ayrıntı için buraya bir göz atın .
def avg(marks):
assert len(marks) != 0,"List is empty."
return sum(marks)/len(marks)
mark2 = [55,88,78,90,79]
print("Average of mark2:",avg(mark2))
mark1 = []
print("Average of mark1:",avg(mark1))
Sadece şunu not edin: Genel istisnaları işlemek istediğiniz zamanlar vardır. Bir grup dosyayı işliyorsanız ve hatalarınızı kaydediyorsanız, bir dosyada oluşan herhangi bir hatayı yakalamak, günlüğe kaydetmek ve diğer dosyaları işlemeye devam etmek isteyebilirsiniz. Bu durumda,
try:
foo()
except Exception as e:
print(str(e)) # Print out handled error
yapmak için iyi bir yol engeller. Yine de raise
belirli istisnalar isteyeceksiniz, böylece ne anlama geldiğini biliyorsunuz.
Bunun için python zam ifadesini öğrenmelisiniz. Deneme bloğunun içinde tutulmalıdır. Misal -
try:
raise TypeError #remove TypeError by any other error if you want
except TypeError:
print('TypeError raised')
raise
ben yığın izini bozmadan kod yürütme birden çok düzeyde özel hata ayıklama gerçekleştirmek için gereken şeydir.