Python try-else


581

elseİfadenin isteğe bağlı maddesinin kullanım amacı nedir try?


1
Çoğu yanıt, malzemeyi neden sadece deneme cümlesindeki diğer maddeye koyamayacağımız üzerinde yoğunlaşıyor gibi görünüyor. Soru stackoverflow.com/questions/3996329 özellikle neden yan tümce kodu neden try bloğundan sonra gidemiyor soruyor ve bu soru bu dupped, ama burada bu soruya net bir cevap görmüyorum. Stackoverflow.com/a/3996378/1503120 bu soruyu mükemmel yanıtladığını hissediyorum . Ayrıca stackoverflow.com/a/22579805/1503120 adresindeki çeşitli maddelerin çeşitli önemlerini açıklamaya çalıştım .
jamadagni

İstisna, son temizleme işleminden önce kendi kendine aynı istisna işlemeyi tetiklememesi gereken bir şeyi tetiklemezse bir şey olmasını istersiniz.
benjimin

Yanıtlar:


858

İfadeler elseyürütme altındaki kapalı düşerse bloğu yürütülür try- istisna olmadığını. Dürüst olmak gerekirse, hiç bir ihtiyaç bulamadım.

Ancak, İstisnalarla İlgili Notlar:

Else yan tümcesinin kullanımı, try deyimi tarafından korunan kod tarafından korunmayan bir istisna yakalamadan kaçındığından, try yan tümcesine ek kod eklemekten daha iyidir.

Eğer, örneğin, bir atmak verebilecek bir yöntem var ise, IOErrorve bunu yükseltir istisnaları yakalamak istiyorum, ama ilk operasyon başarılı olursa yapmak istediğim başka bir şey var ve siz değilsiniz bir IOError yakalamak istiyor bu işlem, şöyle bir şey yazabilirsiniz:

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()

Sadece koyarsanız another_operation_that_can_throw_ioerror()sonra operation_that_can_throw_ioerror, exceptikinci çağrının hatalarını yakalamak istiyorum. Ve tüm trybloktan sonra koyarsanız , her zaman çalıştırılır ve sonrasına kadar değil finally. elseEğer emin olalım

  1. ikinci işlem sadece istisna yoksa çalışır,
  2. finallybloktan önce çalıştırılır ve
  3. IOErroryükselttiği herhangi bir şey burada yakalanmaz

7
Ayrıca try-
block'ta

3
Bu önemli değil, çünkü deneme kapsamındaki değişkenler deneme dışında başka bir şey olup olmadığına bakılıyor.
Reinderien

36
"Deneme kapsamı değişkeni" diye bir şey yoktur. Python'da değişken kapsamlar, kontrol yapıları tarafından değil, sadece modüller, fonksiyonlar ve kavrayışlar tarafından oluşturulur.
mhsmith

9
Else yan tümcesi, yalnızca bir istisna oluşturulmadığında anlamlı olan bir kod yazmanıza olanak tanır; hariç fıkra basitçe geçebilir. Mantığı try bloğuna koyarsanız, kodunuzdaki hataları sessizce gizleme riskiniz vardır. Beklemediğiniz istisnaları asla ezmeyin.
Alice Purcell

9
bu cevaptan "alttan düşme" nin ne anlama geldiği açık değildir - bu sadece bir istisna nedeniyle değil, aynı zamanda a return, continueveya nedeniyle de olur break.
Antti Haapala

108

Kullanmak için büyük bir neden var else- stil ve okunabilirlik. Onlarla ilgilenen kodun yanında istisnalara neden olabilecek kodu tutmak genellikle iyi bir fikirdir. Örneğin, bunları karşılaştırın:

try:
    from EasyDialogs import AskPassword
    # 20 other lines
    getpass = AskPassword
except ImportError:
    getpass = default_getpass

ve

try:
    from EasyDialogs import AskPassword
except ImportError:
    getpass = default_getpass
else:
    # 20 other lines
    getpass = AskPassword

İkincisi, excepterken dönemediğinde veya istisnayı yeniden atamadığında iyidir . Mümkünse şunu yazardım:

try:
    from EasyDialogs import AskPassword
except ImportError:
    getpass = default_getpass
    return False  # or throw Exception('something more descriptive')

# 20 other lines
getpass = AskPassword

Not: Yanıt burada son gönderilen kopyadan kopyalandı , bu nedenle tüm bu "AskPassword" şeyler.


53

Bir kullanım: bir istisnayı yükseltmesi gereken bazı kodları test edin.

try:
    this_should_raise_TypeError()
except TypeError:
    pass
except:
    assert False, "Raised the wrong exception type"
else:
    assert False, "Didn't raise any exception"

(Bu kod pratikte daha genel bir teste tabi tutulmalıdır.)


50

Python try-else

elseTry ifadesinin isteğe bağlı maddesinin kullanım amacı nedir ?

Amaçlanan kullanım, işlenmesi beklenen istisnalar yoksa, daha fazla kodun çalışması için bir içeriğe sahip olmaktır.

Bu bağlam, beklemediğiniz hataların yanlışlıkla giderilmesini önler.

Ama bunun nedeni, kaçak başka maddesini neden kesin koşullarını anlamak önemlidir return, continueve breakkontrol akışını kesintiye uğratabilir else.

Özetle

elseVarsa deyimi çalıştırır hiçbir istisna ve kesintiye değilse return, continueya da breakdeyimi.

Diğer cevaplar bu son kısmı özlüyor.

Dokümanlardan:

Opsiyonel elsefıkra halinde çalıştırılır ve kontrol zaman sonunda kapalı akar ait trymaddesi. *

(Kalın yazı eklendi.) Ve dipnotta şunlar yazıyor:

* Şu anda, kumanda bir istisna veya yürütülmesi durumunda dışında “Sonunda kapalı akar” return, continueya da breakdeyimi.

Madde hariç en az bir tane daha olmasını gerektirir ( bkz. Dilbilgisi ). Yani gerçekten "dene-başkası" değil, ("son-başkası (-nihayet))" ile else(vefinally ) isteğe bağlı.

Python Kılavuzu amaçlanan kullanıma da genişliyor:

Try ... hariç deyimi, varsa tüm maddeler hariç tüm isteğe uyması gereken isteğe bağlı başka bir maddeye sahiptir. Try yan tümcesi bir özel durum oluşturmazsa yürütülmesi gereken kod için kullanışlıdır. Örneğin:

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()

Else yan tümcesinin kullanımı, try deyimi tarafından korunan kod tarafından korunmayan bir istisna yakalamadan kaçındığından, try yan tümcesine ek kod eklemekten daha iyidir.

elseAşağıdaki kod ile farklılaştırma örneğitryBloğu

Bir hatayı ele alırsanız, elseblok çalışmaz. Örneğin:

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!

Ve şimdi,

>>> handle_error()
handled a RuntimeError, no big deal.
And now we have left the try block!

26

Try-hariç-else, EAFP desenini ördek yazma ile birleştirmek için harika :

try:
  cs = x.cleanupSet
except AttributeError:
  pass
else:
  for v in cs:
    v.cleanup()

Bu saf kodun iyi olduğunu düşünebilirsiniz:

try:
  for v in x.cleanupSet:
    v.clenaup()
except AttributeError:
  pass

Bu, kodunuzdaki ciddi hataları yanlışlıkla gizlemenin harika bir yoludur. Orada yazım temizleme yaptım, ama bana haber verecek AttributeError yutuluyor. Daha da kötüsü, doğru yazmış olsaydım, ancak temizleme yöntemi bazen yanlış adlandırılmış bir özniteliğe sahip bir kullanıcı türünden geçiriliyordu, bu da sessizce yarı yolda başarısız olmasına ve bir dosyayı kapatılmamasına neden oldu? Hata ayıklamada iyi şanslar.


19

Bir istisna olsa bile yapılması gereken bir temizlik yaptığınızda bunu gerçekten yararlı buluyorum:

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()

9

Şu anda bir kullanımını düşünemeseniz de, bunun bir kullanımı olması gerektiğine bahse girebilirsiniz. İşte yaratıcı olmayan bir örnek:

İle else:

a = [1,2,3]
try:
    something = a[2]
except:
    print "out of bounds"
else:
    print something

Olmadan else:

try:
    something = a[2]
except:
    print "out of bounds"

if "something" in locals():
    print something

Burada somethingherhangi bir hata verilmezse tanımlanmış değişkeniniz vardır . Bunu tryblok dışında kaldırabilirsiniz , ancak daha sonra bir değişken tanımlanırsa dağınık algılama gerekir.


3
something = a[2]; print somethingTry: block'un içinde yanlış olan ne ?
S.Lott

@ S.Lott hiçbir şey, ama biri size bir liste gönderiyorsa ve eğer muhtemelen bozuk olduğu için yeterince uzun değilse verileri görüntülemek istemiyorsanız ne olacak?
Bilinmiyor

12
S. Lott: 'bir şeyler yazdır', araya girmek istemediğiniz farklı bir istisna oluşturabilir.
Darius Bacon

Farkı görmüyorum. Sınırların dışında bir istisna alırsam, "sınırların dışında" yazdırır. Anladım. Başka bir istisna alırsam, bu kod bloğu tarafından yakalanmaz. İstisna almazsam, davranış bir şeyin değerini yazdırmaktır, ki bu [2]. Bu örnekte başkasının ne yaptığını anlamıyorum.
S.Lott

3
Basıldığında 'bir şeyin' değeri __str __ () yönteminde hatayı artırabilir. Bu değer aslında bu örnekte sadece 2 olsa da, burada da sınırların dışında bir istisna olmadığını belirtebilirsiniz.
Darius Bacon

8

Güzel bir örneği var try-elseiçinde PEP 380 . Temel olarak, algoritmanın farklı bölümlerinde farklı istisna işlemleri yapmaya gelir.

Bunun gibi bir şey:

try:
    do_init_stuff()
except:
    handle_init_suff_execption()
else:
    try:
        do_middle_stuff()
    except:
        handle_middle_stuff_exception()

Bu, kural dışı durum işleme kodunu kural dışı durumun oluştuğu yere yakın yazmanıza olanak tanır.


7

Gönderen istisnalar Handling Hatalar ve İstisnalar # - docs.python.org

try ... exceptİfadesi isteğe bağlı sahiptir elsemevcut, maddeleri dışındaki tüm uymalı, maddeyi,. Try yan tümcesi bir özel durum oluşturmazsa yürütülmesi gereken kod için kullanışlıdır. Örneğin:

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()

Else yan tümcesinin kullanımı, try deyimi tarafından korunan kod tarafından korunmayan bir istisna yakalamadan kaçındığından, try yan tümcesine ek kod eklemekten daha iyidir.


6

Python referansına bakıldığında, istisna olmadığında elseçalıştırıldığı görülüyor try. İsteğe bağlı else yan tümcesi, denetim try yan tümcesinin sonunda akarsa ve ne zaman yürütülür. 2 Diğer fıkrasındaki istisnalar, fıkralar dışında bir önceki fıkra ile ele alınmaz.

Python'a dalın , doğru bir şekilde anlarsam, tryblokta bir modülü içe aktarmaya çalıştıkları, istisna ve varsayılan bağlama yapamadığınızda ancak çalıştığında elsebloğa girip gerekli olanı bağlama seçeneğiniz olduğu bir örneğe sahiptir (bkz. örnek ve açıklama için bağlantı).

Eğer catchblokta çalışmayı denerseniz, başka bir istisna atabilir - sanırım elseblok burada işe yarar.


4
"Else yan tümcesindeki istisnalar, yan tümceler hariç önceki iş tarafından ele alınmaz." Yararlı kısım budur. Teşekkür ederim.
geowa4

"İsteğe bağlı else koşulu ise yürütülür ve kontrol try bloğu sonunda kapalı aktığında" Eğer dışarı dönebilirsiniz beri, başka farktır tryblokta.
Tomer W

4

Bu kadar. Bir try-hariç yantümcesinin 'else' bloğu, denenen işlem başarılı olduğunda (ve yalnızca) çalıştığında kod için vardır. Kullanılabilir ve kötüye kullanılabilir.

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

Şahsen, beğendim ve uygun olduğunda kullanıyorum. Anlamsal olarak ifadeleri gruplandırır.


2

Belki bir kullanım olabilir:

#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()

Belki bu size bir kullanım getirecektir.


2

Ben try: ... else:veritabanı sorguları çalıştırmak ve aynı lezzet / türü ayrı bir veritabanına bu sorguların sonuçlarını günlüğe kaydetme durumda yararlı buldum . Diyelim ki bir kuyruğa gönderilen tüm veritabanı sorgularını işleyen çok sayıda iş parçacığı var

#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

Elbette, atılabilecek olası istisnalar arasında ayrım yapabiliyorsanız, bunu kullanmak zorunda değilsiniz, ancak başarılı bir kod parçasına tepki gösteren kod, başarılı parça ile aynı istisnayı atabilir ve sadece İkinci olası istisnanın gitmesine izin verin veya hemen başarıya dönün (bu benim durumumda iş parçacığını öldürür), o zaman bu kullanışlı olur.


1

Her elseblokta oluşan işlevselliği tamamlamak için genellikle bir blok bulunabilir except.

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.
"""

Bu durumda, inconsistency_typeblok hariç her birinde ayarlanır, böylece davranışı içindeki no-error durumunda tamamlanır else.

Tabii ki, bunu bir gün kendi kodunuzda ortaya çıkabilecek bir model olarak tanımlıyorum. Bu özel durumda, yine inconsistency_typede tryengellemeden önce 0'a ayarladınız .


1

İşte bu deseni kullanmak istediğim başka bir yer:

 while data in items:
     try
        data = json.loads(data)
     except ValueError as e:
        log error
     else:
        # work on the `data`

1
Bunun continueyerine kullanabilirsiniz - "erken kırılma" kalıbı. Bu, kodun okunmasını kolaylaştırmak için "else" yan tümcesini ve girintisini bırakmanıza izin verir.
16:46 malthe malthe

1

Düşünebileceğim kullanım senaryolarından biri, tekrar denerseniz atlatılabilecek öngörülemeyen istisnalar. Örneğin, try bloğundaki işlemler rastgele sayılar içerdiğinde:

while True:
    try:
        r = random.random()
        some_operation_that_fails_for_specific_r(r)
    except Exception:
        continue
    else:
        break

Ancak istisna öngörülebilirse, bir istisna yerine daima doğrulamayı önceden seçmelisiniz. Ancak, her şey tahmin edilemez, bu nedenle bu kod deseninin yeri vardır.


1
Bunu breakiç kısımda, trydaha temiz IMO olan koyarak yapabilirsiniz ve ihtiyacınız yoktur else. Ayrıca continuegerçekten gerekli değildir, sadece yapabilirsiniz pass.
Dirbaio

1

elseMuhtemelen yanlış bir yapılandırma dosyası ile uğraşmak için yararlı buldum :

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

lockYapılandırmayı okuyan bir kural dışı durum kilit izlemeyi devre dışı bırakır ve ValueErrors yardımcı bir uyarı iletisi kaydeder.


1

Programlama mantığınızın, bir sözlüğün belirli bir tuşa sahip bir girişi olup olmadığına bağlı olduğunu varsayalım. Yapı dict.get(key)kullanarak sonucu test edebilir if... else...veya şunları yapabilirsiniz:

try:
    val = dic[key]
except KeyError:
    do_some_stuff()
else:
    do_some_stuff_with_val(val)

-1

DB oturumları işlerken düz görünüyor başka bir kullanım durumu eklemek istiyorum:

    # 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()

-17

else:Blok kafa ve (hemen hemen) işe yaramaz. Ayrıca forve whileifadelerinin bir parçasıdır .

Aslında, bir ifstatüde bile, else:bulmak çok zor böcekler yaratarak gerçekten korkunç yollarla istismar edilebilir.

Bunu düşün.

   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

İki kere düşünün else:. Bu genellikle bir sorundur. Bir durum haricinde bundan kaçının ifve hatta else- durumunu açıkça belirtmek için - koşulunu belgelemeyi düşünün .


6
Buna katılmıyorum. "İf-elif" bloğunda "else", "varsayılan" olarak kullanılır, C dilinin "case" bloğunda kullanılır. Tüm vakaları çeşitli koşullarda ele aldığınızı düşünseniz bile, her zaman "varsayılan" vaka ile ilgilenmeniz önerilir.
Josip

1
@Josip: "varsayılan" olarak kullanılan kafa karıştırıcı olabilir. Sorun bu "varsayılan" durumu açıkça tanımlamaktır. Kötü tanımlanmış bir varsayılan koşul, buggy davranışının temel nedeni olabilir. Başka bir kafa karışıklığı nedeni olabilir. Her durumda çok dikkatli bir şekilde düşünülmelidir, sadece ve bunun için değil, aynı zamanda deneyin.
S.Lott

5
Yukarıdaki kod tamamen soyut ve anlamlı bir şey yapmıyor, bu yüzden evet - kafa karıştırıcı olması şaşırtıcı değil.
julx

1
@ S.Lott "Bu beceriksizliği azaltacaktır" - ve benim görüşüm bunun yanlış olduğu. Bence sadece fikirlerde gerçek bir fark var. Kötü programcılar her zaman buggy programları yazmanın yollarını bulurlar. Her zaman. İyi programcılar her zaman iyi uygulamalar ararlar ve hemen hemen her dilde iyi kod yazabilirler. Yararlı yapıları ortadan kaldırmak, iyi programcılara daha az güç verirken, kötü olanlara özellikle yardımcı olmamakla birlikte, şeyleri bitirmek için sonsuz sayıda yol icat edebildiklerinden.
julx

5
Şunu düşünün: if x > 0: return "yes"ve if x <= 0: return "no". Şimdi bir kişi gelir ve söyleyecek koşullardan x > 1birini değiştirir, ancak diğerini değiştirmeyi unutur. Bu nasıl işlenecek hata sayısını azaltır. if elsecümlecikleri bazen birbirinden ayrı satırlar olur. KURU gerçekten çok iyi bir uygulamadır. (çift yazı için üzgünüm).
julx
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.